PageRenderTime 66ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/rpython/memory/gc/minimark.py

https://bitbucket.org/pypy/pypy/
Python | 2118 lines | 1663 code | 89 blank | 366 comment | 94 complexity | a54137ebf9c427ccba91501d207401bb MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. """ MiniMark GC.
  2. Environment variables can be used to fine-tune the following parameters:
  3. PYPY_GC_NURSERY The nursery size. Defaults to 1/2 of your cache or
  4. '4M'. Small values
  5. (like 1 or 1KB) are useful for debugging.
  6. PYPY_GC_NURSERY_CLEANUP The interval at which nursery is cleaned up. Must
  7. be smaller than the nursery size and bigger than the
  8. biggest object we can allotate in the nursery.
  9. PYPY_GC_MAJOR_COLLECT Major collection memory factor. Default is '1.82',
  10. which means trigger a major collection when the
  11. memory consumed equals 1.82 times the memory
  12. really used at the end of the previous major
  13. collection.
  14. PYPY_GC_GROWTH Major collection threshold's max growth rate.
  15. Default is '1.4'. Useful to collect more often
  16. than normally on sudden memory growth, e.g. when
  17. there is a temporary peak in memory usage.
  18. PYPY_GC_MAX The max heap size. If coming near this limit, it
  19. will first collect more often, then raise an
  20. RPython MemoryError, and if that is not enough,
  21. crash the program with a fatal error. Try values
  22. like '1.6GB'.
  23. PYPY_GC_MAX_DELTA The major collection threshold will never be set
  24. to more than PYPY_GC_MAX_DELTA the amount really
  25. used after a collection. Defaults to 1/8th of the
  26. total RAM size (which is constrained to be at most
  27. 2/3/4GB on 32-bit systems). Try values like '200MB'.
  28. PYPY_GC_MIN Don't collect while the memory size is below this
  29. limit. Useful to avoid spending all the time in
  30. the GC in very small programs. Defaults to 8
  31. times the nursery.
  32. PYPY_GC_DEBUG Enable extra checks around collections that are
  33. too slow for normal use. Values are 0 (off),
  34. 1 (on major collections) or 2 (also on minor
  35. collections).
  36. """
  37. # XXX Should find a way to bound the major collection threshold by the
  38. # XXX total addressable size. Maybe by keeping some minimarkpage arenas
  39. # XXX pre-reserved, enough for a few nursery collections? What about
  40. # XXX raw-malloced memory?
  41. import sys
  42. from rpython.rtyper.lltypesystem import lltype, llmemory, llarena, llgroup
  43. from rpython.rtyper.lltypesystem.lloperation import llop
  44. from rpython.rtyper.lltypesystem.llmemory import raw_malloc_usage
  45. from rpython.memory.gc.base import GCBase, MovingGCBase
  46. from rpython.memory.gc import env
  47. from rpython.memory.support import mangle_hash
  48. from rpython.rlib.rarithmetic import ovfcheck, LONG_BIT, intmask, r_uint
  49. from rpython.rlib.rarithmetic import LONG_BIT_SHIFT
  50. from rpython.rlib.debug import ll_assert, debug_print, debug_start, debug_stop
  51. from rpython.rlib.objectmodel import specialize
  52. #
  53. # Handles the objects in 2 generations:
  54. #
  55. # * young objects: allocated in the nursery if they are not too large, or
  56. # raw-malloced otherwise. The nursery is a fixed-size memory buffer of
  57. # 4MB by default. When full, we do a minor collection;
  58. # the surviving objects from the nursery are moved outside, and the
  59. # non-surviving raw-malloced objects are freed. All surviving objects
  60. # become old.
  61. #
  62. # * old objects: never move again. These objects are either allocated by
  63. # minimarkpage.py (if they are small), or raw-malloced (if they are not
  64. # small). Collected by regular mark-n-sweep during major collections.
  65. #
  66. WORD = LONG_BIT // 8
  67. NULL = llmemory.NULL
  68. first_gcflag = 1 << (LONG_BIT//2)
  69. # The following flag is set on objects if we need to do something to
  70. # track the young pointers that it might contain. The flag is not set
  71. # on young objects (unless they are large arrays, see below), and we
  72. # simply assume that any young object can point to any other young object.
  73. # For old and prebuilt objects, the flag is usually set, and is cleared
  74. # when we write a young pointer to it. For large arrays with
  75. # GCFLAG_HAS_CARDS, we rely on card marking to track where the
  76. # young pointers are; the flag GCFLAG_TRACK_YOUNG_PTRS is set in this
  77. # case too, to speed up the write barrier.
  78. GCFLAG_TRACK_YOUNG_PTRS = first_gcflag << 0
  79. # The following flag is set on some prebuilt objects. The flag is set
  80. # unless the object is already listed in 'prebuilt_root_objects'.
  81. # When a pointer is written inside an object with GCFLAG_NO_HEAP_PTRS
  82. # set, the write_barrier clears the flag and adds the object to
  83. # 'prebuilt_root_objects'.
  84. GCFLAG_NO_HEAP_PTRS = first_gcflag << 1
  85. # The following flag is set on surviving objects during a major collection,
  86. # and on surviving raw-malloced young objects during a minor collection.
  87. GCFLAG_VISITED = first_gcflag << 2
  88. # The following flag is set on nursery objects of which we asked the id
  89. # or the identityhash. It means that a space of the size of the object
  90. # has already been allocated in the nonmovable part. The same flag is
  91. # abused to mark prebuilt objects whose hash has been taken during
  92. # translation and is statically recorded.
  93. GCFLAG_HAS_SHADOW = first_gcflag << 3
  94. # The following flag is set temporarily on some objects during a major
  95. # collection. See pypy/doc/discussion/finalizer-order.txt
  96. GCFLAG_FINALIZATION_ORDERING = first_gcflag << 4
  97. # This flag is reserved for RPython.
  98. GCFLAG_EXTRA = first_gcflag << 5
  99. # The following flag is set on externally raw_malloc'ed arrays of pointers.
  100. # They are allocated with some extra space in front of them for a bitfield,
  101. # one bit per 'card_page_indices' indices.
  102. GCFLAG_HAS_CARDS = first_gcflag << 6
  103. GCFLAG_CARDS_SET = first_gcflag << 7 # <- at least one card bit is set
  104. # note that GCFLAG_CARDS_SET is the most significant bit of a byte:
  105. # this is required for the JIT (x86)
  106. _GCFLAG_FIRST_UNUSED = first_gcflag << 8 # the first unused bit
  107. FORWARDSTUB = lltype.GcStruct('forwarding_stub',
  108. ('forw', llmemory.Address))
  109. FORWARDSTUBPTR = lltype.Ptr(FORWARDSTUB)
  110. NURSARRAY = lltype.Array(llmemory.Address)
  111. # ____________________________________________________________
  112. class MiniMarkGC(MovingGCBase):
  113. _alloc_flavor_ = "raw"
  114. inline_simple_malloc = True
  115. inline_simple_malloc_varsize = True
  116. needs_write_barrier = True
  117. prebuilt_gc_objects_are_static_roots = False
  118. malloc_zero_filled = True # xxx experiment with False
  119. gcflag_extra = GCFLAG_EXTRA
  120. # All objects start with a HDR, i.e. with a field 'tid' which contains
  121. # a word. This word is divided in two halves: the lower half contains
  122. # the typeid, and the upper half contains various flags, as defined
  123. # by GCFLAG_xxx above.
  124. HDR = lltype.Struct('header', ('tid', lltype.Signed))
  125. typeid_is_in_field = 'tid'
  126. withhash_flag_is_in_field = 'tid', GCFLAG_HAS_SHADOW
  127. # ^^^ prebuilt objects may have the flag GCFLAG_HAS_SHADOW;
  128. # then they are one word longer, the extra word storing the hash.
  129. _ADDRARRAY = lltype.Array(llmemory.Address, hints={'nolength': True})
  130. # During a minor collection, the objects in the nursery that are
  131. # moved outside are changed in-place: their header is replaced with
  132. # the value -42, and the following word is set to the address of
  133. # where the object was moved. This means that all objects in the
  134. # nursery need to be at least 2 words long, but objects outside the
  135. # nursery don't need to.
  136. minimal_size_in_nursery = (
  137. llmemory.sizeof(HDR) + llmemory.sizeof(llmemory.Address))
  138. TRANSLATION_PARAMS = {
  139. # Automatically adjust the size of the nursery and the
  140. # 'major_collection_threshold' from the environment.
  141. # See docstring at the start of the file.
  142. "read_from_env": True,
  143. # The size of the nursery. Note that this is only used as a
  144. # fall-back number.
  145. "nursery_size": 896*1024,
  146. # The system page size. Like malloc, we assume that it is 4K
  147. # for 32-bit systems; unlike malloc, we assume that it is 8K
  148. # for 64-bit systems, for consistent results.
  149. "page_size": 1024*WORD,
  150. # The size of an arena. Arenas are groups of pages allocated
  151. # together.
  152. "arena_size": 65536*WORD,
  153. # The maximum size of an object allocated compactly. All objects
  154. # that are larger are just allocated with raw_malloc(). Note that
  155. # the size limit for being first allocated in the nursery is much
  156. # larger; see below.
  157. "small_request_threshold": 35*WORD,
  158. # Full collection threshold: after a major collection, we record
  159. # the total size consumed; and after every minor collection, if the
  160. # total size is now more than 'major_collection_threshold' times,
  161. # we trigger the next major collection.
  162. "major_collection_threshold": 1.82,
  163. # Threshold to avoid that the total heap size grows by a factor of
  164. # major_collection_threshold at every collection: it can only
  165. # grow at most by the following factor from one collection to the
  166. # next. Used e.g. when there is a sudden, temporary peak in memory
  167. # usage; this avoids that the upper bound grows too fast.
  168. "growth_rate_max": 1.4,
  169. # The number of array indices that are mapped to a single bit in
  170. # write_barrier_from_array(). Must be a power of two. The default
  171. # value of 128 means that card pages are 512 bytes (1024 on 64-bits)
  172. # in regular arrays of pointers; more in arrays whose items are
  173. # larger. A value of 0 disables card marking.
  174. "card_page_indices": 128,
  175. # Objects whose total size is at least 'large_object' bytes are
  176. # allocated out of the nursery immediately, as old objects. The
  177. # minimal allocated size of the nursery is 2x the following
  178. # number (by default, at least 132KB on 32-bit and 264KB on 64-bit).
  179. "large_object": (16384+512)*WORD,
  180. # This is the chunk that we cleanup in the nursery. The point is
  181. # to avoid having to trash all the caches just to zero the nursery,
  182. # so we trade it by cleaning it bit-by-bit, as we progress through
  183. # nursery. Has to fit at least one large object
  184. "nursery_cleanup": 32768 * WORD,
  185. }
  186. def __init__(self, config,
  187. read_from_env=False,
  188. nursery_size=32*WORD,
  189. nursery_cleanup=9*WORD,
  190. page_size=16*WORD,
  191. arena_size=64*WORD,
  192. small_request_threshold=5*WORD,
  193. major_collection_threshold=2.5,
  194. growth_rate_max=2.5, # for tests
  195. card_page_indices=0,
  196. large_object=8*WORD,
  197. ArenaCollectionClass=None,
  198. **kwds):
  199. MovingGCBase.__init__(self, config, **kwds)
  200. assert small_request_threshold % WORD == 0
  201. self.read_from_env = read_from_env
  202. self.nursery_size = nursery_size
  203. self.nursery_cleanup = nursery_cleanup
  204. self.small_request_threshold = small_request_threshold
  205. self.major_collection_threshold = major_collection_threshold
  206. self.growth_rate_max = growth_rate_max
  207. self.num_major_collects = 0
  208. self.min_heap_size = 0.0
  209. self.max_heap_size = 0.0
  210. self.max_heap_size_already_raised = False
  211. self.max_delta = float(r_uint(-1))
  212. #
  213. self.card_page_indices = card_page_indices
  214. if self.card_page_indices > 0:
  215. self.card_page_shift = 0
  216. while (1 << self.card_page_shift) < self.card_page_indices:
  217. self.card_page_shift += 1
  218. #
  219. # 'large_object' limit how big objects can be in the nursery, so
  220. # it gives a lower bound on the allowed size of the nursery.
  221. self.nonlarge_max = large_object - 1
  222. #
  223. self.nursery = NULL
  224. self.nursery_free = NULL
  225. self.nursery_top = NULL
  226. self.nursery_real_top = NULL
  227. self.debug_tiny_nursery = -1
  228. self.debug_rotating_nurseries = lltype.nullptr(NURSARRAY)
  229. self.extra_threshold = 0
  230. #
  231. # The ArenaCollection() handles the nonmovable objects allocation.
  232. if ArenaCollectionClass is None:
  233. from rpython.memory.gc import minimarkpage
  234. ArenaCollectionClass = minimarkpage.ArenaCollection
  235. self.ac = ArenaCollectionClass(arena_size, page_size,
  236. small_request_threshold)
  237. #
  238. # Used by minor collection: a list of (mostly non-young) objects that
  239. # (may) contain a pointer to a young object. Populated by
  240. # the write barrier: when we clear GCFLAG_TRACK_YOUNG_PTRS, we
  241. # add it to this list.
  242. # Note that young array objects may (by temporary "mistake") be added
  243. # to this list, but will be removed again at the start of the next
  244. # minor collection.
  245. self.old_objects_pointing_to_young = self.AddressStack()
  246. #
  247. # Similar to 'old_objects_pointing_to_young', but lists objects
  248. # that have the GCFLAG_CARDS_SET bit. For large arrays. Note
  249. # that it is possible for an object to be listed both in here
  250. # and in 'old_objects_pointing_to_young', in which case we
  251. # should just clear the cards and trace it fully, as usual.
  252. # Note also that young array objects are never listed here.
  253. self.old_objects_with_cards_set = self.AddressStack()
  254. #
  255. # A list of all prebuilt GC objects that contain pointers to the heap
  256. self.prebuilt_root_objects = self.AddressStack()
  257. #
  258. self._init_writebarrier_logic()
  259. def setup(self):
  260. """Called at run-time to initialize the GC."""
  261. #
  262. # Hack: MovingGCBase.setup() sets up stuff related to id(), which
  263. # we implement differently anyway. So directly call GCBase.setup().
  264. GCBase.setup(self)
  265. #
  266. # Two lists of all raw_malloced objects (the objects too large)
  267. self.young_rawmalloced_objects = self.null_address_dict()
  268. self.old_rawmalloced_objects = self.AddressStack()
  269. self.rawmalloced_total_size = r_uint(0)
  270. #
  271. # Two lists of all objects with finalizers. Actually they are lists
  272. # of pairs (finalization_queue_nr, object). "probably young objects"
  273. # are all traced and moved to the "old" list by the next minor
  274. # collection.
  275. self.probably_young_objects_with_finalizers = self.AddressDeque()
  276. self.old_objects_with_finalizers = self.AddressDeque()
  277. p = lltype.malloc(self._ADDRARRAY, 1, flavor='raw',
  278. track_allocation=False)
  279. self.singleaddr = llmemory.cast_ptr_to_adr(p)
  280. #
  281. # Two lists of all objects with destructors.
  282. self.young_objects_with_destructors = self.AddressStack()
  283. self.old_objects_with_destructors = self.AddressStack()
  284. #
  285. # Two lists of the objects with weakrefs. No weakref can be an
  286. # old object weakly pointing to a young object: indeed, weakrefs
  287. # are immutable so they cannot point to an object that was
  288. # created after it.
  289. self.young_objects_with_weakrefs = self.AddressStack()
  290. self.old_objects_with_weakrefs = self.AddressStack()
  291. #
  292. # Support for id and identityhash: map nursery objects with
  293. # GCFLAG_HAS_SHADOW to their future location at the next
  294. # minor collection.
  295. self.nursery_objects_shadows = self.AddressDict()
  296. #
  297. # Allocate a nursery. In case of auto_nursery_size, start by
  298. # allocating a very small nursery, enough to do things like look
  299. # up the env var, which requires the GC; and then really
  300. # allocate the nursery of the final size.
  301. if not self.read_from_env:
  302. self.allocate_nursery()
  303. else:
  304. #
  305. defaultsize = self.nursery_size
  306. minsize = 2 * (self.nonlarge_max + 1)
  307. self.nursery_size = minsize
  308. self.allocate_nursery()
  309. #
  310. # From there on, the GC is fully initialized and the code
  311. # below can use it
  312. newsize = env.read_from_env('PYPY_GC_NURSERY')
  313. # PYPY_GC_NURSERY=smallvalue means that minor collects occur
  314. # very frequently; the extreme case is PYPY_GC_NURSERY=1, which
  315. # forces a minor collect for every malloc. Useful to debug
  316. # external factors, like trackgcroot or the handling of the write
  317. # barrier. Implemented by still using 'minsize' for the nursery
  318. # size (needed to handle mallocs just below 'large_objects') but
  319. # hacking at the current nursery position in collect_and_reserve().
  320. if newsize <= 0:
  321. newsize = env.estimate_best_nursery_size()
  322. if newsize <= 0:
  323. newsize = defaultsize
  324. if newsize < minsize:
  325. self.debug_tiny_nursery = newsize & ~(WORD-1)
  326. newsize = minsize
  327. nurs_cleanup = env.read_from_env('PYPY_GC_NURSERY_CLEANUP')
  328. if nurs_cleanup > 0:
  329. self.nursery_cleanup = nurs_cleanup
  330. #
  331. major_coll = env.read_float_from_env('PYPY_GC_MAJOR_COLLECT')
  332. if major_coll > 1.0:
  333. self.major_collection_threshold = major_coll
  334. #
  335. growth = env.read_float_from_env('PYPY_GC_GROWTH')
  336. if growth > 1.0:
  337. self.growth_rate_max = growth
  338. #
  339. min_heap_size = env.read_uint_from_env('PYPY_GC_MIN')
  340. if min_heap_size > 0:
  341. self.min_heap_size = float(min_heap_size)
  342. else:
  343. # defaults to 8 times the nursery
  344. self.min_heap_size = newsize * 8
  345. #
  346. max_heap_size = env.read_uint_from_env('PYPY_GC_MAX')
  347. if max_heap_size > 0:
  348. self.max_heap_size = float(max_heap_size)
  349. #
  350. max_delta = env.read_uint_from_env('PYPY_GC_MAX_DELTA')
  351. if max_delta > 0:
  352. self.max_delta = float(max_delta)
  353. else:
  354. self.max_delta = 0.125 * env.get_total_memory()
  355. #
  356. self.minor_collection() # to empty the nursery
  357. llarena.arena_free(self.nursery)
  358. self.nursery_size = newsize
  359. self.allocate_nursery()
  360. #
  361. if self.nursery_cleanup < self.nonlarge_max + 1:
  362. self.nursery_cleanup = self.nonlarge_max + 1
  363. # We need exactly initial_cleanup + N*nursery_cleanup = nursery_size.
  364. # We choose the value of initial_cleanup to be between 1x and 2x the
  365. # value of nursery_cleanup.
  366. self.initial_cleanup = self.nursery_cleanup + (
  367. self.nursery_size % self.nursery_cleanup)
  368. if (r_uint(self.initial_cleanup) > r_uint(self.nursery_size) or
  369. self.debug_tiny_nursery >= 0):
  370. self.initial_cleanup = self.nursery_size
  371. def _nursery_memory_size(self):
  372. extra = self.nonlarge_max + 1
  373. return self.nursery_size + extra
  374. def _alloc_nursery(self):
  375. # the start of the nursery: we actually allocate a bit more for
  376. # the nursery than really needed, to simplify pointer arithmetic
  377. # in malloc_fixedsize_clear(). The few extra pages are never used
  378. # anyway so it doesn't even count.
  379. nursery = llarena.arena_malloc(self._nursery_memory_size(), 2)
  380. if not nursery:
  381. raise MemoryError("cannot allocate nursery")
  382. return nursery
  383. def allocate_nursery(self):
  384. debug_start("gc-set-nursery-size")
  385. debug_print("nursery size:", self.nursery_size)
  386. self.nursery = self._alloc_nursery()
  387. # the current position in the nursery:
  388. self.nursery_free = self.nursery
  389. # the end of the nursery:
  390. self.nursery_top = self.nursery + self.nursery_size
  391. self.nursery_real_top = self.nursery_top
  392. # initialize the threshold
  393. self.min_heap_size = max(self.min_heap_size, self.nursery_size *
  394. self.major_collection_threshold)
  395. # the following two values are usually equal, but during raw mallocs
  396. # of arrays, next_major_collection_threshold is decremented to make
  397. # the next major collection arrive earlier.
  398. # See translator/c/test/test_newgc, test_nongc_attached_to_gc
  399. self.next_major_collection_initial = self.min_heap_size
  400. self.next_major_collection_threshold = self.min_heap_size
  401. self.set_major_threshold_from(0.0)
  402. ll_assert(self.extra_threshold == 0, "extra_threshold set too early")
  403. self.initial_cleanup = self.nursery_size
  404. debug_stop("gc-set-nursery-size")
  405. def set_major_threshold_from(self, threshold, reserving_size=0):
  406. # Set the next_major_collection_threshold.
  407. threshold_max = (self.next_major_collection_initial *
  408. self.growth_rate_max)
  409. if threshold > threshold_max:
  410. threshold = threshold_max
  411. #
  412. threshold += reserving_size
  413. if threshold < self.min_heap_size:
  414. threshold = self.min_heap_size
  415. #
  416. if self.max_heap_size > 0.0 and threshold > self.max_heap_size:
  417. threshold = self.max_heap_size
  418. bounded = True
  419. else:
  420. bounded = False
  421. #
  422. self.next_major_collection_initial = threshold
  423. self.next_major_collection_threshold = threshold
  424. return bounded
  425. def post_setup(self):
  426. # set up extra stuff for PYPY_GC_DEBUG.
  427. MovingGCBase.post_setup(self)
  428. if self.DEBUG and llarena.has_protect:
  429. # gc debug mode: allocate 23 nurseries instead of just 1,
  430. # and use them alternatively, while mprotect()ing the unused
  431. # ones to detect invalid access.
  432. debug_start("gc-debug")
  433. self.debug_rotating_nurseries = lltype.malloc(
  434. NURSARRAY, 22, flavor='raw', track_allocation=False)
  435. i = 0
  436. while i < 22:
  437. nurs = self._alloc_nursery()
  438. llarena.arena_protect(nurs, self._nursery_memory_size(), True)
  439. self.debug_rotating_nurseries[i] = nurs
  440. i += 1
  441. debug_print("allocated", len(self.debug_rotating_nurseries),
  442. "extra nurseries")
  443. debug_stop("gc-debug")
  444. def debug_rotate_nursery(self):
  445. if self.debug_rotating_nurseries:
  446. debug_start("gc-debug")
  447. oldnurs = self.nursery
  448. llarena.arena_protect(oldnurs, self._nursery_memory_size(), True)
  449. #
  450. newnurs = self.debug_rotating_nurseries[0]
  451. i = 0
  452. while i < len(self.debug_rotating_nurseries) - 1:
  453. self.debug_rotating_nurseries[i] = (
  454. self.debug_rotating_nurseries[i + 1])
  455. i += 1
  456. self.debug_rotating_nurseries[i] = oldnurs
  457. #
  458. llarena.arena_protect(newnurs, self._nursery_memory_size(), False)
  459. self.nursery = newnurs
  460. self.nursery_top = self.nursery + self.initial_cleanup
  461. self.nursery_real_top = self.nursery + self.nursery_size
  462. debug_print("switching from nursery", oldnurs,
  463. "to nursery", self.nursery,
  464. "size", self.nursery_size)
  465. debug_stop("gc-debug")
  466. def malloc_fixedsize_clear(self, typeid, size,
  467. needs_finalizer=False,
  468. is_finalizer_light=False,
  469. contains_weakptr=False):
  470. size_gc_header = self.gcheaderbuilder.size_gc_header
  471. totalsize = size_gc_header + size
  472. rawtotalsize = raw_malloc_usage(totalsize)
  473. #
  474. # If the object needs a finalizer, ask for a rawmalloc.
  475. # The following check should be constant-folded.
  476. if needs_finalizer and not is_finalizer_light:
  477. # old-style finalizers only!
  478. ll_assert(not contains_weakptr,
  479. "'needs_finalizer' and 'contains_weakptr' both specified")
  480. obj = self.external_malloc(typeid, 0, alloc_young=False)
  481. res = llmemory.cast_adr_to_ptr(obj, llmemory.GCREF)
  482. self.register_finalizer(-1, res)
  483. return res
  484. #
  485. # If totalsize is greater than nonlarge_max (which should never be
  486. # the case in practice), ask for a rawmalloc. The following check
  487. # should be constant-folded.
  488. if rawtotalsize > self.nonlarge_max:
  489. ll_assert(not contains_weakptr,
  490. "'contains_weakptr' specified for a large object")
  491. obj = self.external_malloc(typeid, 0, alloc_young=True)
  492. #
  493. else:
  494. # If totalsize is smaller than minimal_size_in_nursery, round it
  495. # up. The following check should also be constant-folded.
  496. min_size = raw_malloc_usage(self.minimal_size_in_nursery)
  497. if rawtotalsize < min_size:
  498. totalsize = rawtotalsize = min_size
  499. #
  500. # Get the memory from the nursery. If there is not enough space
  501. # there, do a collect first.
  502. result = self.nursery_free
  503. self.nursery_free = result + totalsize
  504. if self.nursery_free > self.nursery_top:
  505. result = self.collect_and_reserve(result, totalsize)
  506. #
  507. # Build the object.
  508. llarena.arena_reserve(result, totalsize)
  509. obj = result + size_gc_header
  510. self.init_gc_object(result, typeid, flags=0)
  511. #
  512. # If it is a weakref or has a lightweight destructor, record it
  513. # (checks constant-folded).
  514. if needs_finalizer:
  515. self.young_objects_with_destructors.append(obj)
  516. if contains_weakptr:
  517. self.young_objects_with_weakrefs.append(obj)
  518. return llmemory.cast_adr_to_ptr(obj, llmemory.GCREF)
  519. def malloc_varsize_clear(self, typeid, length, size, itemsize,
  520. offset_to_length):
  521. size_gc_header = self.gcheaderbuilder.size_gc_header
  522. nonvarsize = size_gc_header + size
  523. #
  524. # Compute the maximal length that makes the object still
  525. # below 'nonlarge_max'. All the following logic is usually
  526. # constant-folded because self.nonlarge_max, size and itemsize
  527. # are all constants (the arguments are constant due to
  528. # inlining).
  529. maxsize = self.nonlarge_max - raw_malloc_usage(nonvarsize)
  530. if maxsize < 0:
  531. toobig = r_uint(0) # the nonvarsize alone is too big
  532. elif raw_malloc_usage(itemsize):
  533. toobig = r_uint(maxsize // raw_malloc_usage(itemsize)) + 1
  534. else:
  535. toobig = r_uint(sys.maxint) + 1
  536. if r_uint(length) >= r_uint(toobig):
  537. #
  538. # If the total size of the object would be larger than
  539. # 'nonlarge_max', then allocate it externally. We also
  540. # go there if 'length' is actually negative.
  541. obj = self.external_malloc(typeid, length, alloc_young=True)
  542. #
  543. else:
  544. # With the above checks we know now that totalsize cannot be more
  545. # than 'nonlarge_max'; in particular, the + and * cannot overflow.
  546. totalsize = nonvarsize + itemsize * length
  547. totalsize = llarena.round_up_for_allocation(totalsize)
  548. #
  549. # 'totalsize' should contain at least the GC header and
  550. # the length word, so it should never be smaller than
  551. # 'minimal_size_in_nursery'
  552. ll_assert(raw_malloc_usage(totalsize) >=
  553. raw_malloc_usage(self.minimal_size_in_nursery),
  554. "malloc_varsize_clear(): totalsize < minimalsize")
  555. #
  556. # Get the memory from the nursery. If there is not enough space
  557. # there, do a collect first.
  558. result = self.nursery_free
  559. self.nursery_free = result + totalsize
  560. if self.nursery_free > self.nursery_top:
  561. result = self.collect_and_reserve(result, totalsize)
  562. #
  563. # Build the object.
  564. llarena.arena_reserve(result, totalsize)
  565. self.init_gc_object(result, typeid, flags=0)
  566. #
  567. # Set the length and return the object.
  568. obj = result + size_gc_header
  569. (obj + offset_to_length).signed[0] = length
  570. #
  571. return llmemory.cast_adr_to_ptr(obj, llmemory.GCREF)
  572. def malloc_fixed_or_varsize_nonmovable(self, typeid, length):
  573. # length==0 for fixedsize
  574. obj = self.external_malloc(typeid, length, alloc_young=True)
  575. return llmemory.cast_adr_to_ptr(obj, llmemory.GCREF)
  576. def collect(self, gen=1):
  577. """Do a minor (gen=0) or major (gen>0) collection."""
  578. self.minor_collection()
  579. if gen > 0:
  580. self.major_collection()
  581. def move_nursery_top(self, totalsize):
  582. size = self.nursery_cleanup
  583. ll_assert(self.nursery_real_top - self.nursery_top >= size,
  584. "nursery_cleanup not a divisor of nursery_size - initial_cleanup")
  585. ll_assert(llmemory.raw_malloc_usage(totalsize) <= size,
  586. "totalsize > nursery_cleanup")
  587. llarena.arena_reset(self.nursery_top, size, 2)
  588. self.nursery_top += size
  589. move_nursery_top._always_inline_ = True
  590. def collect_and_reserve(self, prev_result, totalsize):
  591. """To call when nursery_free overflows nursery_top.
  592. First check if the nursery_top is the real top, otherwise we
  593. can just move the top of one cleanup and continue
  594. Do a minor collection, and possibly also a major collection,
  595. and finally reserve 'totalsize' bytes at the start of the
  596. now-empty nursery.
  597. """
  598. if self.nursery_top < self.nursery_real_top:
  599. self.move_nursery_top(totalsize)
  600. return prev_result
  601. self.minor_collection()
  602. #
  603. if self.get_total_memory_used() > self.next_major_collection_threshold:
  604. self.major_collection()
  605. #
  606. # The nursery might not be empty now, because of
  607. # execute_finalizers(). If it is almost full again,
  608. # we need to fix it with another call to minor_collection().
  609. if self.nursery_free + totalsize > self.nursery_top:
  610. #
  611. if self.nursery_free + totalsize > self.nursery_real_top:
  612. self.minor_collection()
  613. # then the nursery is empty
  614. else:
  615. # we just need to clean up a bit more of the nursery
  616. self.move_nursery_top(totalsize)
  617. #
  618. result = self.nursery_free
  619. self.nursery_free = result + totalsize
  620. ll_assert(self.nursery_free <= self.nursery_top, "nursery overflow")
  621. #
  622. if self.debug_tiny_nursery >= 0: # for debugging
  623. if self.nursery_top - self.nursery_free > self.debug_tiny_nursery:
  624. self.nursery_free = self.nursery_top - self.debug_tiny_nursery
  625. #
  626. return result
  627. collect_and_reserve._dont_inline_ = True
  628. # XXX kill alloc_young and make it always True
  629. def external_malloc(self, typeid, length, alloc_young):
  630. """Allocate a large object using the ArenaCollection or
  631. raw_malloc(), possibly as an object with card marking enabled,
  632. if it has gc pointers in its var-sized part. 'length' should be
  633. specified as 0 if the object is not varsized. The returned
  634. object is fully initialized and zero-filled."""
  635. #
  636. # Here we really need a valid 'typeid', not 0 (as the JIT might
  637. # try to send us if there is still a bug).
  638. ll_assert(bool(self.combine(typeid, 0)),
  639. "external_malloc: typeid == 0")
  640. #
  641. # Compute the total size, carefully checking for overflows.
  642. size_gc_header = self.gcheaderbuilder.size_gc_header
  643. nonvarsize = size_gc_header + self.fixed_size(typeid)
  644. if length == 0:
  645. # this includes the case of fixed-size objects, for which we
  646. # should not even ask for the varsize_item_sizes().
  647. totalsize = nonvarsize
  648. elif length > 0:
  649. # var-sized allocation with at least one item
  650. itemsize = self.varsize_item_sizes(typeid)
  651. try:
  652. varsize = ovfcheck(itemsize * length)
  653. totalsize = ovfcheck(nonvarsize + varsize)
  654. except OverflowError:
  655. raise MemoryError
  656. else:
  657. # negative length! This likely comes from an overflow
  658. # earlier. We will just raise MemoryError here.
  659. raise MemoryError
  660. #
  661. # If somebody calls this function a lot, we must eventually
  662. # force a full collection.
  663. if (float(self.get_total_memory_used()) + raw_malloc_usage(totalsize) >
  664. self.next_major_collection_threshold):
  665. self.minor_collection()
  666. self.major_collection(raw_malloc_usage(totalsize))
  667. #
  668. # Check if the object would fit in the ArenaCollection.
  669. # Also, an object allocated from ArenaCollection must be old.
  670. if (raw_malloc_usage(totalsize) <= self.small_request_threshold
  671. and not alloc_young):
  672. #
  673. # Yes. Round up 'totalsize' (it cannot overflow and it
  674. # must remain <= self.small_request_threshold.)
  675. totalsize = llarena.round_up_for_allocation(totalsize)
  676. ll_assert(raw_malloc_usage(totalsize) <=
  677. self.small_request_threshold,
  678. "rounding up made totalsize > small_request_threshold")
  679. #
  680. # Allocate from the ArenaCollection and clear the memory returned.
  681. result = self.ac.malloc(totalsize)
  682. llmemory.raw_memclear(result, totalsize)
  683. #
  684. extra_flags = GCFLAG_TRACK_YOUNG_PTRS
  685. #
  686. else:
  687. # No, so proceed to allocate it externally with raw_malloc().
  688. # Check if we need to introduce the card marker bits area.
  689. if (self.card_page_indices <= 0 # <- this check is constant-folded
  690. or not self.has_gcptr_in_varsize(typeid) or
  691. raw_malloc_usage(totalsize) <= self.nonlarge_max):
  692. #
  693. # In these cases, we don't want a card marker bits area.
  694. # This case also includes all fixed-size objects.
  695. cardheadersize = 0
  696. extra_flags = 0
  697. #
  698. else:
  699. # Reserve N extra words containing card bits before the object.
  700. extra_words = self.card_marking_words_for_length(length)
  701. cardheadersize = WORD * extra_words
  702. extra_flags = GCFLAG_HAS_CARDS | GCFLAG_TRACK_YOUNG_PTRS
  703. # if 'alloc_young', then we also immediately set
  704. # GCFLAG_CARDS_SET, but without adding the object to
  705. # 'old_objects_with_cards_set'. In this way it should
  706. # never be added to that list as long as it is young.
  707. if alloc_young:
  708. extra_flags |= GCFLAG_CARDS_SET
  709. #
  710. # Detect very rare cases of overflows
  711. if raw_malloc_usage(totalsize) > (sys.maxint - (WORD-1)
  712. - cardheadersize):
  713. raise MemoryError("rare case of overflow")
  714. #
  715. # Now we know that the following computations cannot overflow.
  716. # Note that round_up_for_allocation() is also needed to get the
  717. # correct number added to 'rawmalloced_total_size'.
  718. allocsize = (cardheadersize + raw_malloc_usage(
  719. llarena.round_up_for_allocation(totalsize)))
  720. #
  721. # Allocate the object using arena_malloc(), which we assume here
  722. # is just the same as raw_malloc(), but allows the extra
  723. # flexibility of saying that we have extra words in the header.
  724. # The memory returned is cleared by a raw_memclear().
  725. arena = llarena.arena_malloc(allocsize, 2)
  726. if not arena:
  727. raise MemoryError("cannot allocate large object")
  728. #
  729. # Reserve the card mark bits as a list of single bytes
  730. # (the loop is empty in C).
  731. i = 0
  732. while i < cardheadersize:
  733. llarena.arena_reserve(arena + i, llmemory.sizeof(lltype.Char))
  734. i += 1
  735. #
  736. # Reserve the actual object. (This is also a no-op in C).
  737. result = arena + cardheadersize
  738. llarena.arena_reserve(result, totalsize)
  739. #
  740. # Record the newly allocated object and its full malloced size.
  741. # The object is young or old depending on the argument.
  742. self.rawmalloced_total_size += r_uint(allocsize)
  743. if alloc_young:
  744. if not self.young_rawmalloced_objects:
  745. self.young_rawmalloced_objects = self.AddressDict()
  746. self.young_rawmalloced_objects.add(result + size_gc_header)
  747. else:
  748. self.old_rawmalloced_objects.append(result + size_gc_header)
  749. extra_flags |= GCFLAG_TRACK_YOUNG_PTRS
  750. #
  751. # Common code to fill the header and length of the object.
  752. self.init_gc_object(result, typeid, extra_flags)
  753. if self.is_varsize(typeid):
  754. offset_to_length = self.varsize_offset_to_length(typeid)
  755. (result + size_gc_header + offset_to_length).signed[0] = length
  756. return result + size_gc_header
  757. # ----------
  758. # Other functions in the GC API
  759. def set_max_heap_size(self, size):
  760. self.max_heap_size = float(size)
  761. if self.max_heap_size > 0.0:
  762. if self.max_heap_size < self.next_major_collection_initial:
  763. self.next_major_collection_initial = self.max_heap_size
  764. if self.max_heap_size < self.next_major_collection_threshold:
  765. self.next_major_collection_threshold = self.max_heap_size
  766. def raw_malloc_memory_pressure(self, sizehint):
  767. self.next_major_collection_threshold -= sizehint
  768. if self.next_major_collection_threshold < 0:
  769. # cannot trigger a full collection now, but we can ensure
  770. # that one will occur very soon
  771. self.nursery_top = self.nursery_real_top
  772. self.nursery_free = self.nursery_real_top
  773. def can_optimize_clean_setarrayitems(self):
  774. if self.card_page_indices > 0:
  775. return False
  776. return MovingGCBase.can_optimize_clean_setarrayitems(self)
  777. def can_move(self, obj):
  778. """Overrides the parent can_move()."""
  779. return self.is_in_nursery(obj)
  780. def shrink_array(self, obj, smallerlength):
  781. #
  782. # Only objects in the nursery can be "resized". Resizing them
  783. # means recording that they have a smaller size, so that when
  784. # moved out of the nursery, they will consume less memory.
  785. # In particular, an array with GCFLAG_HAS_CARDS is never resized.
  786. # Also, a nursery object with GCFLAG_HAS_SHADOW is not resized
  787. # either, as this would potentially loose part of the memory in
  788. # the already-allocated shadow.
  789. if not self.is_in_nursery(obj):
  790. return False
  791. if self.header(obj).tid & GCFLAG_HAS_SHADOW:
  792. return False
  793. #
  794. size_gc_header = self.gcheaderbuilder.size_gc_header
  795. typeid = self.get_type_id(obj)
  796. totalsmallersize = (
  797. size_gc_header + self.fixed_size(typeid) +
  798. self.varsize_item_sizes(typeid) * smallerlength)
  799. llarena.arena_shrink_obj(obj - size_gc_header, totalsmallersize)
  800. #
  801. offset_to_length = self.varsize_offset_to_length(typeid)
  802. (obj + offset_to_length).signed[0] = smallerlength
  803. return True
  804. # ----------
  805. # Simple helpers
  806. def get_type_id(self, obj):
  807. tid = self.header(obj).tid
  808. return llop.extract_ushort(llgroup.HALFWORD, tid)
  809. def combine(self, typeid16, flags):
  810. return llop.combine_ushort(lltype.Signed, typeid16, flags)
  811. def init_gc_object(self, addr, typeid16, flags=0):
  812. # The default 'flags' is zero. The flags GCFLAG_NO_xxx_PTRS
  813. # have been chosen to allow 'flags' to be zero in the common
  814. # case (hence the 'NO' in their name).
  815. hdr = llmemory.cast_adr_to_ptr(addr, lltype.Ptr(self.HDR))
  816. hdr.tid = self.combine(typeid16, flags)
  817. def init_gc_object_immortal(self, addr, typeid16, flags=0):
  818. # For prebuilt GC objects, the flags must contain
  819. # GCFLAG_NO_xxx_PTRS, at least initially.
  820. flags |= GCFLAG_NO_HEAP_PTRS | GCFLAG_TRACK_YOUNG_PTRS
  821. self.init_gc_object(addr, typeid16, flags)
  822. def is_in_nursery(self, addr):
  823. ll_assert(llmemory.cast_adr_to_int(addr) & 1 == 0,
  824. "odd-valued (i.e. tagged) pointer unexpected here")
  825. return self.nursery <= addr < self.nursery_real_top
  826. def appears_to_be_young(self, addr):
  827. # "is a valid addr to a young object?"
  828. # but it's ok to occasionally return True accidentally.
  829. # Maybe the best implementation would be a bloom filter
  830. # of some kind instead of the dictionary lookup that is
  831. # sometimes done below. But the expected common answer
  832. # is "Yes" because addr points to the nursery, so it may
  833. # not be useful to optimize the other case too much.
  834. #
  835. # First, if 'addr' appears to be a pointer to some place within
  836. # the nursery, return True
  837. if not self.translated_to_c:
  838. # When non-translated, filter out tagged pointers explicitly.
  839. # When translated, it may occasionally give a wrong answer
  840. # of True if 'addr' is a tagged pointer with just the wrong value.
  841. if not self.is_valid_gc_object(addr):
  842. return False
  843. if self.nursery <= addr < self.nursery_real_top:
  844. return True # addr is in the nursery
  845. #
  846. # Else, it may be in the set 'young_rawmalloced_objects'
  847. return (bool(self.young_rawmalloced_objects) and
  848. self.young_rawmalloced_objects.contains(addr))
  849. appears_to_be_young._always_inline_ = True
  850. def debug_is_old_object(self, addr):
  851. return (self.is_valid_gc_object(addr)
  852. and not self.appears_to_be_young(addr))
  853. def is_forwarded(self, obj):
  854. """Returns True if the nursery obj is marked as forwarded.
  855. Implemented a bit obscurely by checking an unrelated flag
  856. that can never be set on a young object -- except if tid == -42.
  857. """
  858. assert self.is_in_nursery(obj)
  859. tid = self.header(obj).tid
  860. result = (tid & GCFLAG_FINALIZATION_ORDERING != 0)
  861. if result:
  862. ll_assert(tid == -42, "bogus header for young obj")
  863. else:
  864. ll_assert(bool(tid), "bogus header (1)")
  865. ll_assert(tid & -_GCFLAG_FIRST_UNUSED == 0, "bogus header (2)")
  866. return result
  867. def get_forwarding_address(self, obj):
  868. return llmemory.cast_adr_to_ptr(obj, FORWARDSTUBPTR).forw
  869. def get_possibly_forwarded_type_id(self, obj):
  870. if self.is_in_nursery(obj) and self.is_forwarded(obj):
  871. obj = self.get_forwarding_address(obj)
  872. return self.get_type_id(obj)
  873. def get_total_memory_used(self):
  874. """Return the total memory used, not counting any object in the
  875. nursery: only objects in the ArenaCollection or raw-malloced.
  876. """
  877. return self.ac.total_memory_used + self.rawmalloced_total_size
  878. def card_marking_words_for_length(self, length):
  879. # --- Unoptimized version:
  880. #num_bits = ((length-1) >> self.card_page_shift) + 1
  881. #return (num_bits + (LONG_BIT - 1)) >> LONG_BIT_SHIFT
  882. # --- Optimized version:
  883. return intmask(
  884. ((r_uint(length) + r_uint((LONG_BIT << self.card_page_shift) - 1)) >>
  885. (self.card_page_shift + LONG_BIT_SHIFT)))
  886. def card_marking_bytes_for_length(self, length):
  887. # --- Unoptimized version:
  888. #num_bits = ((length-1) >> self.card_page_shift) + 1
  889. #return (num_bits + 7) >> 3
  890. # --- Optimized version:
  891. return intmask(
  892. ((r_uint(length) + r_uint((8 << self.card_page_shift) - 1)) >>
  893. (self.card_page_shift + 3)))
  894. def debug_check_consistency(self):
  895. if self.DEBUG:
  896. ll_assert(not self.young_rawmalloced_objects,
  897. "young raw-malloced objects in a major collection")
  898. ll_assert(not self.young_objects_with_weakrefs.non_empty(),
  899. "young objects with weakrefs in a major collection")
  900. MovingGCBase.debug_check_consistency(self)
  901. def debug_check_object(self, obj):
  902. # after a minor or major collection, no object should be in the nursery
  903. ll_assert(not self.is_in_nursery(obj),
  904. "object in nursery after collection")
  905. # similarily, all objects should have this flag, except if they
  906. # don't have any GC pointer
  907. typeid = self.get_type_id(obj)
  908. if self.has_gcptr(typeid):
  909. ll_assert(self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS != 0,
  910. "missing GCFLAG_TRACK_YOUNG_PTRS")
  911. # the GCFLAG_VISITED should not be set between collections
  912. ll_assert(self.header(obj).tid & GCFLAG_VISITED == 0,
  913. "unexpected GCFLAG_VISITED")
  914. # the GCFLAG_FINALIZATION_ORDERING should not be set between coll.
  915. ll_assert(self.header(obj).tid & GCFLAG_FINALIZATION_ORDERING == 0,
  916. "unexpected GCFLAG_FINALIZATION_ORDERING")
  917. # the GCFLAG_CARDS_SET should not be set between collections
  918. ll_assert(self.header(obj).tid & GCFLAG_CARDS_SET == 0,
  919. "unexpected GCFLAG_CARDS_SET")
  920. # if the GCFLAG_HAS_CARDS is set, check that all bits are zero now
  921. if self.header(obj).tid & GCFLAG_HAS_CARDS:
  922. if self.card_page_indices <= 0:
  923. ll_assert(False, "GCFLAG_HAS_CARDS but not using card marking")
  924. return
  925. typeid = self.get_type_id(obj)
  926. ll_assert(self.has_gcptr_in_varsize(typeid),
  927. "GCFLAG_HAS_CARDS but not has_gcptr_in_varsize")
  928. ll_assert(self.header(obj).tid & GCFLAG_NO_HEAP_PTRS == 0,
  929. "GCFLAG_HAS_CARDS && GCFLAG_NO_HEAP_PTRS")
  930. offset_to_length = self.varsize_offset_to_length(typeid)
  931. length = (obj + offset_to_length).signed[0]
  932. extra_words = self.card_marking_words_for_length(length)
  933. #
  934. size_gc_header = self.gcheaderbuilder.size_gc_header
  935. p = llarena.getfakearenaaddress(obj - size_gc_header)
  936. i = extra_words * WORD
  937. while i > 0:
  938. p -= 1
  939. ll_assert(p.char[0] == '\x00',
  940. "the card marker bits are not cleared")
  941. i -= 1
  942. # ----------
  943. # Write barrier
  944. # for the JIT: a minimal description of the write_barrier() method
  945. # (the JIT assumes it is of the shape
  946. # "if addr_struct.int0 & JIT_WB_IF_FLAG: remember_young_pointer()")
  947. JIT_WB_IF_FLAG = GCFLAG_TRACK_YOUNG_PTRS
  948. # for the JIT to generate custom code corresponding to the array
  949. # write barrier for the simplest case of cards. If JIT_CARDS_SET
  950. # is already set on an object, it will execute code like this:
  951. # MOV eax, index
  952. # SHR eax, JIT_WB_CARD_PAGE_SHIFT
  953. # XOR eax, -8
  954. # BTS [object], eax
  955. if TRANSLATION_PARAMS['card_page_indices'] > 0:
  956. JIT_WB_CARDS_SET = GCFLAG_CARDS_SET
  957. JIT_WB_CARD_PAGE_SHIFT = 1
  958. while ((1 << JIT_WB_CARD_PAGE_SHIFT) !=
  959. TRANSLATION_PARAMS['card_page_indices']):
  960. JIT_WB_CARD_PAGE_SHIFT += 1
  961. @classmethod
  962. def JIT_max_size_of_young_obj(cls):
  963. return cls.TRANSLATION_PARAMS['large_object']
  964. @classmethod
  965. def JIT_minimal_size_in_nursery(cls):
  966. return cls.minimal_size_in_nursery
  967. def write_barrier(self, addr_struct):
  968. if self.header(addr_struct).tid & GCFLAG_TRACK_YOUNG_PTRS:
  969. self.remember_young_pointer(addr_struct)
  970. def write_barrier_from_array(self, addr_array, index):
  971. if self.header(addr_array).tid & GCFLAG_TRACK_YOUNG_PTRS:
  972. if self.card_page_indices > 0: # <- constant-folded
  973. self.remember_young_pointer_from_array2(addr_array, index)
  974. else:
  975. self.remember_young_pointer(addr_array)
  976. def _init_writebarrier_logic(self):
  977. DEBUG = self.DEBUG
  978. # The purpose of attaching remember_young_pointer to the instance
  979. # instead of keeping it as a regular method is to
  980. # make the code in write_barrier() marginally smaller
  981. # (which is important because it is inlined *everywhere*).
  982. def remember_young_pointer(addr_struct):
  983. # 'addr_struct' is the address of the object in which we write.
  984. # We know that 'addr_struct' has GCFLAG_TRACK_YOUNG_PTRS so far.
  985. #
  986. if DEBUG: # note: PYPY_GC_DEBUG=1 does not enable this
  987. ll_assert(self.debug_is_old_object(addr_struct) or
  988. self.header(addr_struct).tid & GCFLAG_HAS_CARDS != 0,
  989. "young object with GCFLAG_TRACK_YOUNG_PTRS and no cards")
  990. #
  991. # We need to remove the flag GCFLAG_TRACK_YOUNG_PTRS and add
  992. # the object to the list 'old_objects_pointing_to_young'.
  993. # We know that 'addr_struct' cannot be in the nursery,
  994. # because nursery objects never have the flag
  995. # GCFLAG_TRACK_YOUNG_PTRS to start with. Note that in
  996. # theory we don't need to do that if the pointer that we're
  997. # writing into the object isn't pointing to a young object.
  998. # However, it isn't really a win, because then sometimes
  999. # we're going to call this function a lot of times for the
  1000. # same object; moreover we'd need to pass the 'newvalue' as
  1001. # an argument here. The JIT has always called a
  1002. # 'newvalue'-less version, too.
  1003. self.old_objects_pointing_to_young.append(addr_struct)
  1004. objhdr = self.header(addr_struct)
  1005. objhdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS
  1006. #
  1007. # Second part: if 'addr_struct' is actually a prebuilt GC
  1008. # object and it's the first time we see a write to it, we
  1009. # add it to the list 'prebuilt_root_objects'.
  1010. if objhdr.tid & GCFLAG_NO_HEAP_PTRS:
  1011. objhdr.tid &= ~GCFLAG_NO_HEAP_PTRS
  1012. self.prebuilt_root_objects.append(addr_struct)
  1013. remember_young_pointer._dont_inline_ = True
  1014. self.remember_young_pointer = remember_young_pointer
  1015. #
  1016. if self.card_page_indices > 0:
  1017. self._init_writebarrier_with_card_marker()
  1018. def _init_writebarrier_with_card_marker(self):
  1019. DEBUG = self.DEBUG
  1020. def remember_young_pointer_from_array2(addr_array, index):
  1021. # 'addr_array' is the address of the object in which we write,
  1022. # which must have an array part; 'index' is the index of the
  1023. # item that is (or contains) the pointer that we write.
  1024. # We know that 'addr_array' has GCFLAG_TRACK_YOUNG_PTRS so far.
  1025. #
  1026. objhdr = self.header(addr_array)
  1027. if objhdr.tid & GCFLAG_HAS_CARDS == 0:
  1028. #
  1029. if DEBUG: # note: PYPY_GC_DEBUG=1 does not enable this
  1030. ll_assert(self.debug_is_old_object(addr_array),
  1031. "young array with no card but GCFLAG_TRACK_YOUNG_PTRS")
  1032. #
  1033. # no cards, use default logic. Mostly copied from above.
  1034. self.old_objects_pointing_to_young.append(addr_array)
  1035. objhdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS
  1036. if objhdr.tid & GCFLAG_NO_HEAP_PTRS:
  1037. objhdr.tid &= ~GCFLAG_NO_HEAP_PTRS
  1038. self.prebuilt_root_objects.append(addr_array)
  1039. return
  1040. #
  1041. # 'addr_array' is a raw_malloc'ed array with card markers
  1042. # in front. Compute the index of the bit to set:
  1043. bitindex = index >> self.card_page_shift
  1044. byteindex = bitindex >> 3
  1045. bitmask = 1 << (bitindex & 7)
  1046. #
  1047. # If the bit is already set, leave now.
  1048. addr_byte = self.get_card(addr_array, byteindex)
  1049. byte = ord(addr_byte.char[0])
  1050. if byte & bitmask:
  1051. return
  1052. #
  1053. # We set the flag (even if the newly written address does not
  1054. # actually point to the nursery, which seems to be ok -- actually
  1055. # it seems more important that remember_young_pointer_from_array2()
  1056. # does not take 3 arguments).
  1057. addr_byte.char[0] = chr(byte | bitmask)
  1058. #
  1059. if objhdr.tid & GCFLAG_CARDS_SET == 0:
  1060. self.old_objects_with_cards_set.append(addr_array)
  1061. objhdr.tid |= GCFLAG_CARDS_SET
  1062. remember_young_pointer_from_array2._dont_inline_ = True
  1063. assert self.card_page_indices > 0
  1064. self.remember_young_pointer_from_array2 = (
  1065. remember_young_pointer_from_array2)
  1066. def jit_remember_young_pointer_from_array(addr_array):
  1067. # minimal version of the above, with just one argument,
  1068. # called by the JIT when GCFLAG_TRACK_YOUNG_PTRS is set
  1069. # but GCFLAG_CARDS_SET is cleared. This tries to set
  1070. # GCFLAG_CARDS_SET if possible; otherwise, it falls back
  1071. # to remember_young_pointer().
  1072. objhdr = self.header(addr_array)
  1073. if objhdr.tid & GCFLAG_HAS_CARDS:
  1074. self.old_objects_with_cards_set.append(addr_array)
  1075. objhdr.tid |= GCFLAG_CARDS_SET
  1076. else:
  1077. self.remember_young_pointer(addr_array)
  1078. self.jit_remember_young_pointer_from_array = (
  1079. jit_remember_young_pointer_from_array)
  1080. def get_card(self, obj, byteindex):
  1081. size_gc_header = self.gcheaderbuilder.size_gc_header
  1082. addr_byte = obj - size_gc_header
  1083. return llarena.getfakearenaaddress(addr_byte) + (~byteindex)
  1084. def writebarrier_before_copy(self, source_addr, dest_addr,
  1085. source_start, dest_start, length):
  1086. """ This has the same effect as calling writebarrier over
  1087. each element in dest copied from source, except it might reset
  1088. one of the following flags a bit too eagerly, which means we'll have
  1089. a bit more objects to track, but being on the safe side.
  1090. """
  1091. source_hdr = self.header(source_addr)
  1092. dest_hdr = self.header(dest_addr)
  1093. if dest_hdr.tid & GCFLAG_TRACK_YOUNG_PTRS == 0:
  1094. return True
  1095. # ^^^ a fast path of write-barrier
  1096. #
  1097. if source_hdr.tid & GCFLAG_HAS_CARDS != 0:
  1098. #
  1099. if source_hdr.tid & GCFLAG_TRACK_YOUNG_PTRS == 0:
  1100. # The source object may have random young pointers.
  1101. # Return False to mean "do it manually in ll_arraycopy".
  1102. return False
  1103. #
  1104. if source_hdr.tid & GCFLAG_CARDS_SET == 0:
  1105. # The source object has no young pointers at all. Done.
  1106. return True
  1107. #
  1108. if dest_hdr.tid & GCFLAG_HAS_CARDS == 0:
  1109. # The dest object doesn't have cards. Do it manually.
  1110. return False
  1111. #
  1112. if source_start != 0 or dest_start != 0:
  1113. # Misaligned. Do it manually.
  1114. return False
  1115. #
  1116. self.manually_copy_card_bits(source_addr, dest_addr, length)
  1117. return True
  1118. #
  1119. if source_hdr.tid & GCFLAG_TRACK_YOUNG_PTRS == 0:
  1120. # there might be in source a pointer to a young object
  1121. self.old_objects_pointing_to_young.append(dest_addr)
  1122. dest_hdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS
  1123. #
  1124. if dest_hdr.tid & GCFLAG_NO_HEAP_PTRS:
  1125. if source_hdr.tid & GCFLAG_NO_HEAP_PTRS == 0:
  1126. dest_hdr.tid &= ~GCFLAG_NO_HEAP_PTRS
  1127. self.prebuilt_root_objects.append(dest_addr)
  1128. return True
  1129. def manually_copy_card_bits(self, source_addr, dest_addr, length):
  1130. # manually copy the individual card marks from source to dest
  1131. assert self.card_page_indices > 0
  1132. bytes = self.card_marking_bytes_for_length(length)
  1133. #
  1134. anybyte = 0
  1135. i = 0
  1136. while i < bytes:
  1137. addr_srcbyte = self.get_card(source_addr, i)
  1138. addr_dstbyte = self.get_card(dest_addr, i)
  1139. byte = ord(addr_srcbyte.char[0])
  1140. anybyte |= byte
  1141. addr_dstbyte.char[0] = chr(ord(addr_dstbyte.char[0]) | byte)
  1142. i += 1
  1143. #
  1144. if anybyte:
  1145. dest_hdr = self.header(dest_addr)
  1146. if dest_hdr.tid & GCFLAG_CARDS_SET == 0:
  1147. self.old_objects_with_cards_set.append(dest_addr)
  1148. dest_hdr.tid |= GCFLAG_CARDS_SET
  1149. def register_finalizer(self, fq_index, gcobj):
  1150. from rpython.rtyper.lltypesystem import rffi
  1151. obj = llmemory.cast_ptr_to_adr(gcobj)
  1152. fq_index = rffi.cast(llmemory.Address, fq_index)
  1153. self.probably_young_objects_with_finalizers.append(obj)
  1154. self.probably_young_objects_with_finalizers.append(fq_index)
  1155. # ----------
  1156. # Nursery collection
  1157. def minor_collection(self):
  1158. """Perform a minor collection: find the objects from the nursery
  1159. that remain alive and move them out."""
  1160. #
  1161. debug_start("gc-minor")
  1162. #
  1163. # Before everything else, remove from 'old_objects_pointing_to_young'
  1164. # the young arrays.
  1165. if self.young_rawmalloced_objects:
  1166. self.remove_young_arrays_from_old_objects_pointing_to_young()
  1167. #
  1168. # First, find the roots that point to young objects. All nursery
  1169. # objects found are copied out of the nursery, and the occasional
  1170. # young raw-malloced object is flagged with GCFLAG_VISITED.
  1171. # Note that during this step, we ignore references to further
  1172. # young objects; only objects directly referenced by roots
  1173. # are copied out or flagged. They are also added to the list
  1174. # 'old_objects_pointing_to_young'.
  1175. self.collect_roots_in_nursery()
  1176. #
  1177. # visit the "probably young" objects with finalizers. They
  1178. # always all survive.
  1179. if self.probably_young_objects_with_finalizers.non_empty():
  1180. self.deal_with_young_objects_with_finalizers()
  1181. #
  1182. while True:
  1183. # If we are using card marking, do a partial trace of the arrays
  1184. # that are flagged with GCFLAG_CARDS_SET.
  1185. if self.card_page_indices > 0:
  1186. self.collect_cardrefs_to_nursery()
  1187. #
  1188. # Now trace objects from 'old_objects_pointing_to_young'.
  1189. # All nursery objects they reference are copied out of the
  1190. # nursery, and again added to 'old_objects_pointing_to_young'.
  1191. # All young raw-malloced object found are flagged GCFLAG_VISITED.
  1192. # We proceed until 'old_objects_pointing_to_young' is empty.
  1193. self.collect_oldrefs_to_nursery()
  1194. #
  1195. # We have to loop back if collect_oldrefs_to_nursery caused
  1196. # new objects to show up in old_objects_with_cards_set
  1197. if self.card_page_indices > 0:
  1198. if self.old_objects_with_cards_set.non_empty():
  1199. continue
  1200. break
  1201. #
  1202. # Now all live nursery objects should be out. Update the young
  1203. # weakrefs' targets.
  1204. if self.young_objects_with_weakrefs.non_empty():
  1205. self.invalidate_young_weakrefs()
  1206. if self.young_objects_with_destructors.non_empty():
  1207. self.deal_with_young_objects_with_destructors()
  1208. #
  1209. # Clear this mapping.
  1210. if self.nursery_objects_shadows.length() > 0:
  1211. self.nursery_objects_shadows.clear()
  1212. #
  1213. # Walk the list of young raw-malloced objects, and either free
  1214. # them or make them old.
  1215. if self.young_rawmalloced_objects:
  1216. self.free_young_rawmalloced_objects()
  1217. #
  1218. # All live nursery objects are out, and the rest dies. Fill
  1219. # the nursery up to the cleanup point with zeros
  1220. llarena.arena_reset(self.nursery, self.nursery_size, 0)
  1221. llarena.arena_reset(self.nursery, self.initial_cleanup, 2)
  1222. self.debug_rotate_nursery()
  1223. self.nursery_free = self.nursery
  1224. self.nursery_top = self.nursery + self.initial_cleanup
  1225. self.nursery_real_top = self.nursery + self.nursery_size
  1226. #
  1227. debug_print("minor collect, total memory used:",
  1228. self.get_total_memory_used())
  1229. if self.DEBUG >= 2:
  1230. self.debug_check_consistency() # expensive!
  1231. debug_stop("gc-minor")
  1232. def collect_roots_in_nursery(self):
  1233. # we don't need to trace prebuilt GcStructs during a minor collect:
  1234. # if a prebuilt GcStruct contains a pointer to a young object,
  1235. # then the write_barrier must have ensured that the prebuilt
  1236. # GcStruct is in the list self.old_objects_pointing_to_young.
  1237. debug_start("gc-minor-walkroots")
  1238. self.root_walker.walk_roots(
  1239. MiniMarkGC._trace_drag_out1, # stack roots
  1240. MiniMarkGC._trace_drag_out1, # static in prebuilt non-gc
  1241. None, # static in prebuilt gc
  1242. is_minor=True)
  1243. debug_stop("gc-minor-walkroots")
  1244. def collect_cardrefs_to_nursery(self):
  1245. size_gc_header = self.gcheaderbuilder.size_gc_header
  1246. oldlist = self.old_objects_with_cards_set
  1247. while oldlist.non_empty():
  1248. obj = oldlist.pop()
  1249. #
  1250. # Remove the GCFLAG_CARDS_SET flag.
  1251. ll_assert(self.header(obj).tid & GCFLAG_CARDS_SET != 0,
  1252. "!GCFLAG_CARDS_SET but object in 'old_objects_with_cards_set'")
  1253. self.header(obj).tid &= ~GCFLAG_CARDS_SET
  1254. #
  1255. # Get the number of card marker bytes in the header.
  1256. typeid = self.get_type_id(obj)
  1257. offset_to_length = self.varsize_offset_to_length(typeid)
  1258. length = (obj + offset_to_length).signed[0]
  1259. bytes = self.card_marking_bytes_for_length(length)
  1260. p = llarena.getfakearenaaddress(obj - size_gc_header)
  1261. #
  1262. # If the object doesn't have GCFLAG_TRACK_YOUNG_PTRS, then it
  1263. # means that it is in 'old_objects_pointing_to_young' and
  1264. # will be fully traced by collect_oldrefs_to_nursery() just
  1265. # afterwards.
  1266. if self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS == 0:
  1267. #
  1268. # In that case, we just have to reset all card bits.
  1269. while bytes > 0:
  1270. p -= 1
  1271. p.char[0] = '\x00'
  1272. bytes -= 1
  1273. #
  1274. else:
  1275. # Walk the bytes encoding the card marker bits, and for
  1276. # each bit set, call trace_and_drag_out_of_nursery_partial().
  1277. interval_start = 0
  1278. while bytes > 0:
  1279. p -= 1
  1280. cardbyte = ord(p.char[0])
  1281. p.char[0] = '\x00' # reset the bits
  1282. bytes -= 1
  1283. next_byte_start = interval_start + 8*self.card_page_indices
  1284. #
  1285. while cardbyte != 0:
  1286. interval_stop = interval_start + self.card_page_indices
  1287. #
  1288. if cardbyte & 1:
  1289. if interval_stop > length:
  1290. interval_stop = length
  1291. ll_assert(cardbyte <= 1 and bytes == 0,
  1292. "premature end of object")
  1293. self.trace_and_drag_out_of_nursery_partial(
  1294. obj, interval_start, interval_stop)
  1295. #
  1296. interval_start = interval_stop
  1297. cardbyte >>= 1
  1298. interval_start = next_byte_start
  1299. def collect_oldrefs_to_nursery(self):
  1300. # Follow the old_objects_pointing_to_young list and move the
  1301. # young objects they point to out of the nursery.
  1302. oldlist = self.old_objects_pointing_to_young
  1303. while oldlist.non_empty():
  1304. obj = oldlist.pop()
  1305. #
  1306. # Check that the flags are correct: we must not have
  1307. # GCFLAG_TRACK_YOUNG_PTRS so far.
  1308. ll_assert(self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS == 0,
  1309. "old_objects_pointing_to_young contains obj with "
  1310. "GCFLAG_TRACK_YOUNG_PTRS")
  1311. #
  1312. # Add the flag GCFLAG_TRACK_YOUNG_PTRS. All live objects should
  1313. # have this flag set after a nursery collection.
  1314. self.header(obj).tid |= GCFLAG_TRACK_YOUNG_PTRS
  1315. #
  1316. # Trace the 'obj' to replace pointers to nursery with pointers
  1317. # outside the nursery, possibly forcing nursery objects out
  1318. # and adding them to 'old_objects_pointing_to_young' as well.
  1319. self.trace_and_drag_out_of_nursery(obj)
  1320. def trace_and_drag_out_of_nursery(self, obj):
  1321. """obj must not be in the nursery. This copies all the
  1322. young objects it references out of the nursery.
  1323. """
  1324. self.trace(obj, self._trace_drag_out, None)
  1325. def trace_and_drag_out_of_nursery_partial(self, obj, start, stop):
  1326. """Like trace_and_drag_out_of_nursery(), but limited to the array
  1327. indices in range(start, stop).
  1328. """
  1329. ll_assert(start < stop, "empty or negative range "
  1330. "in trace_and_drag_out_of_nursery_partial()")
  1331. #print 'trace_partial:', start, stop, '\t', obj
  1332. self.trace_partial(obj, start, stop, self._trace_drag_out, None)
  1333. def _trace_drag_out1(self, root):
  1334. self._trace_drag_out(root, None)
  1335. def _trace_drag_out(self, root, ignored):
  1336. obj = root.address[0]
  1337. #print '_trace_drag_out(%x: %r)' % (hash(obj.ptr._obj), obj)
  1338. #
  1339. # If 'obj' is not in the nursery, nothing to change -- expect
  1340. # that we must set GCFLAG_VISITED on young raw-malloced objects.
  1341. if not self.is_in_nursery(obj):
  1342. # cache usage trade-off: I think that it is a better idea to
  1343. # check if 'obj' is in young_rawmalloced_objects with an access
  1344. # to this (small) dictionary, rather than risk a lot of cache
  1345. # misses by reading a flag in the header of all the 'objs' that
  1346. # arrive here.
  1347. if (bool(self.young_rawmalloced_objects)
  1348. and self.young_rawmalloced_objects.contains(obj)):
  1349. self._visit_young_rawmalloced_object(obj)
  1350. return
  1351. #
  1352. size_gc_header = self.gcheaderbuilder.size_gc_header
  1353. if self.header(obj).tid & GCFLAG_HAS_SHADOW == 0:
  1354. #
  1355. # Common case: 'obj' was not already forwarded (otherwise
  1356. # tid == -42, containing all flags), and it doesn't have the
  1357. # HAS_SHADOW flag either. We must move it out of the nursery,
  1358. # into a new nonmovable location.
  1359. totalsize = size_gc_header + self.get_size(obj)
  1360. newhdr = self._malloc_out_of_nursery(totalsize)
  1361. #
  1362. elif self.is_forwarded(obj):
  1363. #
  1364. # 'obj' was already forwarded. Change the original reference
  1365. # to point to its forwarding address, and we're done.
  1366. root.address[0] = self.get_forwarding_address(obj)
  1367. return
  1368. #
  1369. else:
  1370. # First visit to an object that has already a shadow.
  1371. newobj = self.nursery_objects_shadows.get(obj)
  1372. ll_assert(newobj != NULL, "GCFLAG_HAS_SHADOW but no shadow found")
  1373. newhdr = newobj - size_gc_header
  1374. #
  1375. # Remove the flag GCFLAG_HAS_SHADOW, so that it doesn't get
  1376. # copied to the shadow itself.
  1377. self.header(obj).tid &= ~GCFLAG_HAS_SHADOW
  1378. #
  1379. totalsize = size_gc_header + self.get_size(obj)
  1380. #
  1381. # Copy it. Note that references to other objects in the
  1382. # nursery are kept unchanged in this step.
  1383. llmemory.raw_memcopy(obj - size_gc_header, newhdr, totalsize)
  1384. #
  1385. # Set the old object's tid to -42 (containing all flags) and
  1386. # replace the old object's content with the target address.
  1387. # A bit of no-ops to convince llarena that we are changing
  1388. # the layout, in non-translated versions.
  1389. typeid = self.get_type_id(obj)
  1390. obj = llarena.getfakearenaaddress(obj)
  1391. llarena.arena_reset(obj - size_gc_header, totalsize, 0)
  1392. llarena.arena_reserve(obj - size_gc_header,
  1393. size_gc_header + llmemory.sizeof(FORWARDSTUB))
  1394. self.header(obj).tid = -42
  1395. newobj = newhdr + size_gc_header
  1396. llmemory.cast_adr_to_ptr(obj, FORWARDSTUBPTR).forw = newobj
  1397. #
  1398. # Change the original pointer to this object.
  1399. root.address[0] = newobj
  1400. #
  1401. # Add the newobj to the list 'old_objects_pointing_to_young',
  1402. # because it can contain further pointers to other young objects.
  1403. # We will fix such references to point to the copy of the young
  1404. # objects when we walk 'old_objects_pointing_to_young'.
  1405. if self.has_gcptr(typeid):
  1406. # we only have to do it if we have any gcptrs
  1407. self.old_objects_pointing_to_young.append(newobj)
  1408. _trace_drag_out._always_inline_ = True
  1409. def _visit_young_rawmalloced_object(self, obj):
  1410. # 'obj' points to a young, raw-malloced object.
  1411. # Any young rawmalloced object never seen by the code here
  1412. # will end up without GCFLAG_VISITED, and be freed at the
  1413. # end of the current minor collection. Note that there was
  1414. # a bug in which dying young arrays with card marks would
  1415. # still be scanned before being freed, keeping a lot of
  1416. # objects unnecessarily alive.
  1417. hdr = self.header(obj)
  1418. if hdr.tid & GCFLAG_VISITED:
  1419. return
  1420. hdr.tid |= GCFLAG_VISITED
  1421. #
  1422. # we just made 'obj' old, so we need to add it to the correct lists
  1423. added_somewhere = False
  1424. #
  1425. if hdr.tid & GCFLAG_TRACK_YOUNG_PTRS == 0:
  1426. self.old_objects_pointing_to_young.append(obj)
  1427. added_somewhere = True
  1428. #
  1429. if hdr.tid & GCFLAG_HAS_CARDS != 0:
  1430. ll_assert(hdr.tid & GCFLAG_CARDS_SET != 0,
  1431. "young array: GCFLAG_HAS_CARDS without GCFLAG_CARDS_SET")
  1432. self.old_objects_with_cards_set.append(obj)
  1433. added_somewhere = True
  1434. #
  1435. ll_assert(added_somewhere, "wrong flag combination on young array")
  1436. def _malloc_out_of_nursery(self, totalsize):
  1437. """Allocate non-movable memory for an object of the given
  1438. 'totalsize' that lives so far in the nursery."""
  1439. if raw_malloc_usage(totalsize) <= self.small_request_threshold:
  1440. # most common path
  1441. return self.ac.malloc(totalsize)
  1442. else:
  1443. # for nursery objects that are not small
  1444. return self._malloc_out_of_nursery_nonsmall(totalsize)
  1445. _malloc_out_of_nursery._always_inline_ = True
  1446. def _malloc_out_of_nursery_nonsmall(self, totalsize):
  1447. # 'totalsize' should be aligned.
  1448. ll_assert(raw_malloc_usage(totalsize) & (WORD-1) == 0,
  1449. "misaligned totalsize in _malloc_out_of_nursery_nonsmall")
  1450. #
  1451. arena = llarena.arena_malloc(raw_malloc_usage(totalsize), False)
  1452. if not arena:
  1453. raise MemoryError("cannot allocate object")
  1454. llarena.arena_reserve(arena, totalsize)
  1455. #
  1456. size_gc_header = self.gcheaderbuilder.size_gc_header
  1457. self.rawmalloced_total_size += r_uint(raw_malloc_usage(totalsize))
  1458. self.old_rawmalloced_objects.append(arena + size_gc_header)
  1459. return arena
  1460. def free_young_rawmalloced_objects(self):
  1461. self.young_rawmalloced_objects.foreach(
  1462. self._free_young_rawmalloced_obj, None)
  1463. self.young_rawmalloced_objects.delete()
  1464. self.young_rawmalloced_objects = self.null_address_dict()
  1465. def _free_young_rawmalloced_obj(self, obj, ignored1, ignored2):
  1466. # If 'obj' has GCFLAG_VISITED, it was seen by _trace_drag_out
  1467. # and survives. Otherwise, it dies.
  1468. self.free_rawmalloced_object_if_unvisited(obj)
  1469. def remove_young_arrays_from_old_objects_pointing_to_young(self):
  1470. old = self.old_objects_pointing_to_young
  1471. new = self.AddressStack()
  1472. while old.non_empty():
  1473. obj = old.pop()
  1474. if not self.young_rawmalloced_objects.contains(obj):
  1475. new.append(obj)
  1476. # an extra copy, to avoid assignments to
  1477. # 'self.old_objects_pointing_to_young'
  1478. while new.non_empty():
  1479. old.append(new.pop())
  1480. new.delete()
  1481. # ----------
  1482. # Full collection
  1483. def major_collection(self, reserving_size=0):
  1484. """Do a major collection. Only for when the nursery is empty."""
  1485. #
  1486. debug_start("gc-collect")
  1487. debug_print()
  1488. debug_print(".----------- Full collection ------------------")
  1489. debug_print("| used before collection:")
  1490. debug_print("| in ArenaCollection: ",
  1491. self.ac.total_memory_used, "bytes")
  1492. debug_print("| raw_malloced: ",
  1493. self.rawmalloced_total_size, "bytes")
  1494. #
  1495. # Debugging checks
  1496. ll_assert(self.nursery_free == self.nursery,
  1497. "nursery not empty in major_collection()")
  1498. self.debug_check_consistency()
  1499. #
  1500. # Note that a major collection is non-moving. The goal is only to
  1501. # find and free some of the objects allocated by the ArenaCollection.
  1502. # We first visit all objects and toggle the flag GCFLAG_VISITED on
  1503. # them, starting from the roots.
  1504. self.objects_to_trace = self.AddressStack()
  1505. self.collect_roots()
  1506. self.visit_all_objects()
  1507. #
  1508. # Finalizer support: adds the flag GCFLAG_VISITED to all objects
  1509. # with a finalizer and all objects reachable from there (and also
  1510. # moves some objects from 'objects_with_finalizers' to
  1511. # 'run_finalizers').
  1512. if self.old_objects_with_finalizers.non_empty():
  1513. self.deal_with_objects_with_finalizers()
  1514. #
  1515. self.objects_to_trace.delete()
  1516. #
  1517. # Weakref support: clear the weak pointers to dying objects
  1518. if self.old_objects_with_weakrefs.non_empty():
  1519. self.invalidate_old_weakrefs()
  1520. if self.old_objects_with_destructors.non_empty():
  1521. self.deal_with_old_objects_with_destructors()
  1522. #
  1523. # Walk all rawmalloced objects and free the ones that don't
  1524. # have the GCFLAG_VISITED flag.
  1525. self.free_unvisited_rawmalloc_objects()
  1526. #
  1527. # Ask the ArenaCollection to visit all objects. Free the ones
  1528. # that have not been visited above, and reset GCFLAG_VISITED on
  1529. # the others.
  1530. self.ac.mass_free(self._free_if_unvisited)
  1531. #
  1532. # We also need to reset the GCFLAG_VISITED on prebuilt GC objects.
  1533. self.prebuilt_root_objects.foreach(self._reset_gcflag_visited, None)
  1534. #
  1535. self.debug_check_consistency()
  1536. #
  1537. self.num_major_collects += 1
  1538. debug_print("| used after collection:")
  1539. debug_print("| in ArenaCollection: ",
  1540. self.ac.total_memory_used, "bytes")
  1541. debug_print("| raw_malloced: ",
  1542. self.rawmalloced_total_size, "bytes")
  1543. debug_print("| number of major collects: ",
  1544. self.num_major_collects)
  1545. debug_print("`----------------------------------------------")
  1546. debug_stop("gc-collect")
  1547. #
  1548. # Set the threshold for the next major collection to be when we
  1549. # have allocated 'major_collection_threshold' times more than
  1550. # we currently have -- but no more than 'max_delta' more than
  1551. # we currently have.
  1552. total_memory_used = float(self.get_total_memory_used())
  1553. bounded = self.set_major_threshold_from(
  1554. min(total_memory_used * self.major_collection_threshold,
  1555. total_memory_used + self.max_delta),
  1556. reserving_size)
  1557. #
  1558. # Max heap size: gives an upper bound on the threshold. If we
  1559. # already have at least this much allocated, raise MemoryError.
  1560. if bounded and (float(self.get_total_memory_used()) + reserving_size >=
  1561. self.next_major_collection_initial):
  1562. #
  1563. # First raise MemoryError, giving the program a chance to
  1564. # quit cleanly. It might still allocate in the nursery,
  1565. # which might eventually be emptied, triggering another
  1566. # major collect and (possibly) reaching here again with an
  1567. # even higher memory consumption. To prevent it, if it's
  1568. # the second time we are here, then abort the program.
  1569. if self.max_heap_size_already_raised:
  1570. llop.debug_fatalerror(lltype.Void,
  1571. "Using too much memory, aborting")
  1572. self.max_heap_size_already_raised = True
  1573. raise MemoryError
  1574. #
  1575. # At the end, we can execute the finalizers of the objects
  1576. # listed in 'run_finalizers'. Note that this will typically do
  1577. # more allocations.
  1578. self.execute_finalizers()
  1579. def _free_if_unvisited(self, hdr):
  1580. size_gc_header = self.gcheaderbuilder.size_gc_header
  1581. obj = hdr + size_gc_header
  1582. if self.header(obj).tid & GCFLAG_VISITED:
  1583. self.header(obj).tid &= ~GCFLAG_VISITED
  1584. return False # survives
  1585. return True # dies
  1586. def _reset_gcflag_visited(self, obj, ignored):
  1587. self.header(obj).tid &= ~GCFLAG_VISITED
  1588. def free_rawmalloced_object_if_unvisited(self, obj):
  1589. if self.header(obj).tid & GCFLAG_VISITED:
  1590. self.header(obj).tid &= ~GCFLAG_VISITED # survives
  1591. self.old_rawmalloced_objects.append(obj)
  1592. else:
  1593. size_gc_header = self.gcheaderbuilder.size_gc_header
  1594. totalsize = size_gc_header + self.get_size(obj)
  1595. allocsize = raw_malloc_usage(totalsize)
  1596. arena = llarena.getfakearenaaddress(obj - size_gc_header)
  1597. #
  1598. # Must also include the card marker area, if any
  1599. if (self.card_page_indices > 0 # <- this is constant-folded
  1600. and self.header(obj).tid & GCFLAG_HAS_CARDS):
  1601. #
  1602. # Get the length and compute the number of extra bytes
  1603. typeid = self.get_type_id(obj)
  1604. ll_assert(self.has_gcptr_in_varsize(typeid),
  1605. "GCFLAG_HAS_CARDS but not has_gcptr_in_varsize")
  1606. offset_to_length = self.varsize_offset_to_length(typeid)
  1607. length = (obj + offset_to_length).signed[0]
  1608. extra_words = self.card_marking_words_for_length(length)
  1609. arena -= extra_words * WORD
  1610. allocsize += extra_words * WORD
  1611. #
  1612. llarena.arena_free(arena)
  1613. self.rawmalloced_total_size -= r_uint(allocsize)
  1614. def free_unvisited_rawmalloc_objects(self):
  1615. list = self.old_rawmalloced_objects
  1616. self.old_rawmalloced_objects = self.AddressStack()
  1617. #
  1618. while list.non_empty():
  1619. self.free_rawmalloced_object_if_unvisited(list.pop())
  1620. #
  1621. list.delete()
  1622. def collect_roots(self):
  1623. # Collect all roots. Starts from all the objects
  1624. # from 'prebuilt_root_objects'.
  1625. self.prebuilt_root_objects.foreach(self._collect_obj,
  1626. self.objects_to_trace)
  1627. #
  1628. # Add the roots from the other sources.
  1629. self.root_walker.walk_roots(
  1630. MiniMarkGC._collect_ref_stk, # stack roots
  1631. MiniMarkGC._collect_ref_stk, # static in prebuilt non-gc structures
  1632. None) # we don't need the static in all prebuilt gc objects
  1633. #
  1634. # If we are in an inner collection caused by a call to a finalizer,
  1635. # the 'run_finalizers' objects also need to be kept alive.
  1636. self.enum_pending_finalizers(self._collect_obj,
  1637. self.objects_to_trace)
  1638. def enumerate_all_roots(self, callback, arg):
  1639. self.prebuilt_root_objects.foreach(callback, arg)
  1640. MovingGCBase.enumerate_all_roots(self, callback, arg)
  1641. enumerate_all_roots._annspecialcase_ = 'specialize:arg(1)'
  1642. @staticmethod
  1643. def _collect_obj(obj, objects_to_trace):
  1644. objects_to_trace.append(obj)
  1645. def _collect_ref_stk(self, root):
  1646. obj = root.address[0]
  1647. llop.debug_nonnull_pointer(lltype.Void, obj)
  1648. self.objects_to_trace.append(obj)
  1649. def _collect_ref_rec(self, root, ignored):
  1650. self.objects_to_trace.append(root.address[0])
  1651. def visit_all_objects(self):
  1652. pending = self.objects_to_trace
  1653. while pending.non_empty():
  1654. obj = pending.pop()
  1655. self.visit(obj)
  1656. def visit(self, obj):
  1657. #
  1658. # 'obj' is a live object. Check GCFLAG_VISITED to know if we
  1659. # have already seen it before.
  1660. #
  1661. # Moreover, we can ignore prebuilt objects with GCFLAG_NO_HEAP_PTRS.
  1662. # If they have this flag set, then they cannot point to heap
  1663. # objects, so ignoring them is fine. If they don't have this
  1664. # flag set, then the object should be in 'prebuilt_root_objects',
  1665. # and the GCFLAG_VISITED will be reset at the end of the
  1666. # collection.
  1667. hdr = self.header(obj)
  1668. if hdr.tid & (GCFLAG_VISITED | GCFLAG_NO_HEAP_PTRS):
  1669. return
  1670. #
  1671. # It's the first time. We set the flag.
  1672. hdr.tid |= GCFLAG_VISITED
  1673. if not self.has_gcptr(llop.extract_ushort(llgroup.HALFWORD, hdr.tid)):
  1674. return
  1675. #
  1676. # Trace the content of the object and put all objects it references
  1677. # into the 'objects_to_trace' list.
  1678. self.trace(obj, self._collect_ref_rec, None)
  1679. # ----------
  1680. # id() and identityhash() support
  1681. def _allocate_shadow(self, obj):
  1682. size_gc_header = self.gcheaderbuilder.size_gc_header
  1683. size = self.get_size(obj)
  1684. shadowhdr = self._malloc_out_of_nursery(size_gc_header +
  1685. size)
  1686. # Initialize the shadow enough to be considered a
  1687. # valid gc object. If the original object stays
  1688. # alive at the next minor collection, it will anyway
  1689. # be copied over the shadow and overwrite the
  1690. # following fields. But if the object dies, then
  1691. # the shadow will stay around and only be freed at
  1692. # the next major collection, at which point we want
  1693. # it to look valid (but ready to be freed).
  1694. shadow = shadowhdr + size_gc_header
  1695. self.header(shadow).tid = self.header(obj).tid
  1696. typeid = self.get_type_id(obj)
  1697. if self.is_varsize(typeid):
  1698. lenofs = self.varsize_offset_to_length(typeid)
  1699. (shadow + lenofs).signed[0] = (obj + lenofs).signed[0]
  1700. #
  1701. self.header(obj).tid |= GCFLAG_HAS_SHADOW
  1702. self.nursery_objects_shadows.setitem(obj, shadow)
  1703. return shadow
  1704. def _find_shadow(self, obj):
  1705. #
  1706. # The object is not a tagged pointer, and it is still in the
  1707. # nursery. Find or allocate a "shadow" object, which is
  1708. # where the object will be moved by the next minor
  1709. # collection
  1710. if self.header(obj).tid & GCFLAG_HAS_SHADOW:
  1711. shadow = self.nursery_objects_shadows.get(obj)
  1712. ll_assert(shadow != NULL,
  1713. "GCFLAG_HAS_SHADOW but no shadow found")
  1714. else:
  1715. shadow = self._allocate_shadow(obj)
  1716. #
  1717. # The answer is the address of the shadow.
  1718. return shadow
  1719. _find_shadow._dont_inline_ = True
  1720. @specialize.arg(2)
  1721. def id_or_identityhash(self, gcobj, is_hash):
  1722. """Implement the common logic of id() and identityhash()
  1723. of an object, given as a GCREF.
  1724. """
  1725. obj = llmemory.cast_ptr_to_adr(gcobj)
  1726. #
  1727. if self.is_valid_gc_object(obj):
  1728. if self.is_in_nursery(obj):
  1729. obj = self._find_shadow(obj)
  1730. elif is_hash:
  1731. if self.header(obj).tid & GCFLAG_HAS_SHADOW:
  1732. #
  1733. # For identityhash(), we need a special case for some
  1734. # prebuilt objects: their hash must be the same before
  1735. # and after translation. It is stored as an extra word
  1736. # after the object. But we cannot use it for id()
  1737. # because the stored value might clash with a real one.
  1738. size = self.get_size(obj)
  1739. i = (obj + size).signed[0]
  1740. # Important: the returned value is not mangle_hash()ed!
  1741. return i
  1742. #
  1743. i = llmemory.cast_adr_to_int(obj)
  1744. if is_hash:
  1745. i = mangle_hash(i)
  1746. return i
  1747. id_or_identityhash._always_inline_ = True
  1748. def id(self, gcobj):
  1749. return self.id_or_identityhash(gcobj, False)
  1750. def identityhash(self, gcobj):
  1751. return self.id_or_identityhash(gcobj, True)
  1752. # ----------
  1753. # Finalizers
  1754. def deal_with_young_objects_with_destructors(self):
  1755. """We can reasonably assume that destructors don't do
  1756. anything fancy and *just* call them. Among other things
  1757. they won't resurrect objects
  1758. """
  1759. while self.young_objects_with_destructors.non_empty():
  1760. obj = self.young_objects_with_destructors.pop()
  1761. if not self.is_forwarded(obj):
  1762. self.call_destructor(obj)
  1763. else:
  1764. obj = self.get_forwarding_address(obj)
  1765. self.old_objects_with_destructors.append(obj)
  1766. def deal_with_old_objects_with_destructors(self):
  1767. """We can reasonably assume that destructors don't do
  1768. anything fancy and *just* call them. Among other things
  1769. they won't resurrect objects
  1770. """
  1771. new_objects = self.AddressStack()
  1772. while self.old_objects_with_destructors.non_empty():
  1773. obj = self.old_objects_with_destructors.pop()
  1774. if self.header(obj).tid & GCFLAG_VISITED:
  1775. # surviving
  1776. new_objects.append(obj)
  1777. else:
  1778. # dying
  1779. self.call_destructor(obj)
  1780. self.old_objects_with_destructors.delete()
  1781. self.old_objects_with_destructors = new_objects
  1782. def deal_with_young_objects_with_finalizers(self):
  1783. while self.probably_young_objects_with_finalizers.non_empty():
  1784. obj = self.probably_young_objects_with_finalizers.popleft()
  1785. fq_nr = self.probably_young_objects_with_finalizers.popleft()
  1786. self.singleaddr.address[0] = obj
  1787. self._trace_drag_out1(self.singleaddr)
  1788. obj = self.singleaddr.address[0]
  1789. self.old_objects_with_finalizers.append(obj)
  1790. self.old_objects_with_finalizers.append(fq_nr)
  1791. def deal_with_objects_with_finalizers(self):
  1792. # Walk over list of objects with finalizers.
  1793. # If it is not surviving, add it to the list of to-be-called
  1794. # finalizers and make it survive, to make the finalizer runnable.
  1795. # We try to run the finalizers in a "reasonable" order, like
  1796. # CPython does. The details of this algorithm are in
  1797. # pypy/doc/discussion/finalizer-order.txt.
  1798. new_with_finalizer = self.AddressDeque()
  1799. marked = self.AddressDeque()
  1800. pending = self.AddressStack()
  1801. self.tmpstack = self.AddressStack()
  1802. while self.old_objects_with_finalizers.non_empty():
  1803. x = self.old_objects_with_finalizers.popleft()
  1804. fq_nr = self.old_objects_with_finalizers.popleft()
  1805. ll_assert(self._finalization_state(x) != 1,
  1806. "bad finalization state 1")
  1807. if self.header(x).tid & GCFLAG_VISITED:
  1808. new_with_finalizer.append(x)
  1809. new_with_finalizer.append(fq_nr)
  1810. continue
  1811. marked.append(x)
  1812. marked.append(fq_nr)
  1813. pending.append(x)
  1814. while pending.non_empty():
  1815. y = pending.pop()
  1816. state = self._finalization_state(y)
  1817. if state == 0:
  1818. self._bump_finalization_state_from_0_to_1(y)
  1819. self.trace(y, self._append_if_nonnull, pending)
  1820. elif state == 2:
  1821. self._recursively_bump_finalization_state_from_2_to_3(y)
  1822. self._recursively_bump_finalization_state_from_1_to_2(x)
  1823. while marked.non_empty():
  1824. x = marked.popleft()
  1825. fq_nr = marked.popleft()
  1826. state = self._finalization_state(x)
  1827. ll_assert(state >= 2, "unexpected finalization state < 2")
  1828. if state == 2:
  1829. from rpython.rtyper.lltypesystem import rffi
  1830. fq_index = rffi.cast(lltype.Signed, fq_nr)
  1831. self.mark_finalizer_to_run(fq_index, x)
  1832. # we must also fix the state from 2 to 3 here, otherwise
  1833. # we leave the GCFLAG_FINALIZATION_ORDERING bit behind
  1834. # which will confuse the next collection
  1835. self._recursively_bump_finalization_state_from_2_to_3(x)
  1836. else:
  1837. new_with_finalizer.append(x)
  1838. new_with_finalizer.append(fq_nr)
  1839. self.tmpstack.delete()
  1840. pending.delete()
  1841. marked.delete()
  1842. self.old_objects_with_finalizers.delete()
  1843. self.old_objects_with_finalizers = new_with_finalizer
  1844. def _append_if_nonnull(pointer, stack):
  1845. stack.append(pointer.address[0])
  1846. _append_if_nonnull = staticmethod(_append_if_nonnull)
  1847. def _finalization_state(self, obj):
  1848. tid = self.header(obj).tid
  1849. if tid & GCFLAG_VISITED:
  1850. if tid & GCFLAG_FINALIZATION_ORDERING:
  1851. return 2
  1852. else:
  1853. return 3
  1854. else:
  1855. if tid & GCFLAG_FINALIZATION_ORDERING:
  1856. return 1
  1857. else:
  1858. return 0
  1859. def _bump_finalization_state_from_0_to_1(self, obj):
  1860. ll_assert(self._finalization_state(obj) == 0,
  1861. "unexpected finalization state != 0")
  1862. hdr = self.header(obj)
  1863. hdr.tid |= GCFLAG_FINALIZATION_ORDERING
  1864. def _recursively_bump_finalization_state_from_2_to_3(self, obj):
  1865. ll_assert(self._finalization_state(obj) == 2,
  1866. "unexpected finalization state != 2")
  1867. pending = self.tmpstack
  1868. ll_assert(not pending.non_empty(), "tmpstack not empty")
  1869. pending.append(obj)
  1870. while pending.non_empty():
  1871. y = pending.pop()
  1872. hdr = self.header(y)
  1873. if hdr.tid & GCFLAG_FINALIZATION_ORDERING: # state 2 ?
  1874. hdr.tid &= ~GCFLAG_FINALIZATION_ORDERING # change to state 3
  1875. self.trace(y, self._append_if_nonnull, pending)
  1876. def _recursively_bump_finalization_state_from_1_to_2(self, obj):
  1877. # recursively convert objects from state 1 to state 2.
  1878. # The call to visit_all_objects() will add the GCFLAG_VISITED
  1879. # recursively.
  1880. self.objects_to_trace.append(obj)
  1881. self.visit_all_objects()
  1882. # ----------
  1883. # Weakrefs
  1884. # The code relies on the fact that no weakref can be an old object
  1885. # weakly pointing to a young object. Indeed, weakrefs are immutable
  1886. # so they cannot point to an object that was created after it.
  1887. # Thanks to this, during a minor collection, we don't have to fix
  1888. # or clear the address stored in old weakrefs.
  1889. def invalidate_young_weakrefs(self):
  1890. """Called during a nursery collection."""
  1891. # walk over the list of objects that contain weakrefs and are in the
  1892. # nursery. if the object it references survives then update the
  1893. # weakref; otherwise invalidate the weakref
  1894. while self.young_objects_with_weakrefs.non_empty():
  1895. obj = self.young_objects_with_weakrefs.pop()
  1896. if not self.is_forwarded(obj):
  1897. continue # weakref itself dies
  1898. obj = self.get_forwarding_address(obj)
  1899. offset = self.weakpointer_offset(self.get_type_id(obj))
  1900. pointing_to = (obj + offset).address[0]
  1901. if self.is_in_nursery(pointing_to):
  1902. if self.is_forwarded(pointing_to):
  1903. (obj + offset).address[0] = self.get_forwarding_address(
  1904. pointing_to)
  1905. else:
  1906. (obj + offset).address[0] = llmemory.NULL
  1907. continue # no need to remember this weakref any longer
  1908. #
  1909. elif (bool(self.young_rawmalloced_objects) and
  1910. self.young_rawmalloced_objects.contains(pointing_to)):
  1911. # young weakref to a young raw-malloced object
  1912. if self.header(pointing_to).tid & GCFLAG_VISITED:
  1913. pass # survives, but does not move
  1914. else:
  1915. (obj + offset).address[0] = llmemory.NULL
  1916. continue # no need to remember this weakref any longer
  1917. #
  1918. elif self.header(pointing_to).tid & GCFLAG_NO_HEAP_PTRS:
  1919. # see test_weakref_to_prebuilt: it's not useful to put
  1920. # weakrefs into 'old_objects_with_weakrefs' if they point
  1921. # to a prebuilt object (they are immortal). If moreover
  1922. # the 'pointing_to' prebuilt object still has the
  1923. # GCFLAG_NO_HEAP_PTRS flag, then it's even wrong, because
  1924. # 'pointing_to' will not get the GCFLAG_VISITED during
  1925. # the next major collection. Solve this by not registering
  1926. # the weakref into 'old_objects_with_weakrefs'.
  1927. continue
  1928. #
  1929. self.old_objects_with_weakrefs.append(obj)
  1930. def invalidate_old_weakrefs(self):
  1931. """Called during a major collection."""
  1932. # walk over list of objects that contain weakrefs
  1933. # if the object it references does not survive, invalidate the weakref
  1934. new_with_weakref = self.AddressStack()
  1935. while self.old_objects_with_weakrefs.non_empty():
  1936. obj = self.old_objects_with_weakrefs.pop()
  1937. if self.header(obj).tid & GCFLAG_VISITED == 0:
  1938. continue # weakref itself dies
  1939. offset = self.weakpointer_offset(self.get_type_id(obj))
  1940. pointing_to = (obj + offset).address[0]
  1941. ll_assert((self.header(pointing_to).tid & GCFLAG_NO_HEAP_PTRS)
  1942. == 0, "registered old weakref should not "
  1943. "point to a NO_HEAP_PTRS obj")
  1944. if self.header(pointing_to).tid & GCFLAG_VISITED:
  1945. new_with_weakref.append(obj)
  1946. else:
  1947. (obj + offset).address[0] = llmemory.NULL
  1948. self.old_objects_with_weakrefs.delete()
  1949. self.old_objects_with_weakrefs = new_with_weakref