PageRenderTime 35ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/mono/metadata/sgen-minor-copy-object.h

https://bitbucket.org/danipen/mono
C Header | 304 lines | 162 code | 46 blank | 96 comment | 31 complexity | 5ec177c254e0f2a68d49f9422357c392 MD5 | raw file
Possible License(s): Unlicense, Apache-2.0, LGPL-2.0, MPL-2.0-no-copyleft-exception, CC-BY-SA-3.0, GPL-2.0
  1. /*
  2. * sgen-minor-copy-object.h: Copy functions for nursery collections.
  3. *
  4. * Copyright 2001-2003 Ximian, Inc
  5. * Copyright 2003-2010 Novell, Inc.
  6. * Copyright (C) 2012 Xamarin Inc
  7. *
  8. * This library is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU Library General Public
  10. * License 2.0 as published by the Free Software Foundation;
  11. *
  12. * This library is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Library General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Library General Public
  18. * License 2.0 along with this library; if not, write to the Free
  19. * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20. */
  21. #define collector_pin_object(obj, queue) sgen_pin_object (obj, queue);
  22. #define COLLECTOR_SERIAL_ALLOC_FOR_PROMOTION alloc_for_promotion
  23. #define COLLECTOR_PARALLEL_ALLOC_FOR_PROMOTION par_alloc_for_promotion
  24. extern long long stat_nursery_copy_object_failed_to_space; /* from sgen-gc.c */
  25. #include "sgen-copy-object.h"
  26. /*
  27. * This is how the copying happens from the nursery to the old generation.
  28. * We assume that at this time all the pinned objects have been identified and
  29. * marked as such.
  30. * We run scan_object() for each pinned object so that each referenced
  31. * objects if possible are copied. The new gray objects created can have
  32. * scan_object() run on them right away, too.
  33. * Then we run copy_object() for the precisely tracked roots. At this point
  34. * all the roots are either gray or black. We run scan_object() on the gray
  35. * objects until no more gray objects are created.
  36. * At the end of the process we walk again the pinned list and we unmark
  37. * the pinned flag. As we go we also create the list of free space for use
  38. * in the next allocation runs.
  39. *
  40. * We need to remember objects from the old generation that point to the new one
  41. * (or just addresses?).
  42. *
  43. * copy_object could be made into a macro once debugged (use inline for now).
  44. */
  45. #ifdef _MSC_VER
  46. static __forceinline void
  47. #else
  48. static inline void __attribute__((always_inline))
  49. #endif
  50. SERIAL_COPY_OBJECT (void **obj_slot, SgenGrayQueue *queue)
  51. {
  52. char *forwarded;
  53. char *obj = *obj_slot;
  54. SGEN_ASSERT (9, current_collection_generation == GENERATION_NURSERY, "calling minor-serial-copy from a %d generation collection", current_collection_generation);
  55. HEAVY_STAT (++stat_copy_object_called_nursery);
  56. if (!sgen_ptr_in_nursery (obj)) {
  57. HEAVY_STAT (++stat_nursery_copy_object_failed_from_space);
  58. return;
  59. }
  60. SGEN_LOG (9, "Precise copy of %p from %p", obj, obj_slot);
  61. /*
  62. * Before we can copy the object we must make sure that we are
  63. * allowed to, i.e. that the object not pinned, not already
  64. * forwarded or belongs to the nursery To Space.
  65. */
  66. if ((forwarded = SGEN_OBJECT_IS_FORWARDED (obj))) {
  67. SGEN_ASSERT (9, (*(MonoVTable**)SGEN_LOAD_VTABLE (obj))->gc_descr, "forwarded object %p has no gc descriptor", forwarded);
  68. SGEN_LOG (9, " (already forwarded to %p)", forwarded);
  69. HEAVY_STAT (++stat_nursery_copy_object_failed_forwarded);
  70. *obj_slot = forwarded;
  71. return;
  72. }
  73. if (G_UNLIKELY (SGEN_OBJECT_IS_PINNED (obj))) {
  74. SGEN_ASSERT (9, ((MonoVTable*)SGEN_LOAD_VTABLE(obj))->gc_descr, "pinned object %p has no gc descriptor", obj);
  75. SGEN_LOG (9, " (pinned, no change)");
  76. HEAVY_STAT (++stat_nursery_copy_object_failed_pinned);
  77. return;
  78. }
  79. #ifndef SGEN_SIMPLE_NURSERY
  80. if (sgen_nursery_is_to_space (obj)) {
  81. SGEN_ASSERT (9, ((MonoVTable*)SGEN_LOAD_VTABLE(obj))->gc_descr, "to space object %p has no gc descriptor", obj);
  82. SGEN_LOG (9, " (tospace, no change)");
  83. HEAVY_STAT (++stat_nursery_copy_object_failed_to_space);
  84. return;
  85. }
  86. #endif
  87. HEAVY_STAT (++stat_objects_copied_nursery);
  88. *obj_slot = copy_object_no_checks (obj, queue);
  89. }
  90. /*
  91. * SERIAL_COPY_OBJECT_FROM_OBJ:
  92. *
  93. * Similar to SERIAL_COPY_OBJECT, but assumes that OBJ_SLOT is part of an object, so it handles global remsets as well.
  94. */
  95. #ifdef _MSC_VER
  96. static __forceinline void
  97. #else
  98. static inline void __attribute__((always_inline))
  99. #endif
  100. SERIAL_COPY_OBJECT_FROM_OBJ (void **obj_slot, SgenGrayQueue *queue)
  101. {
  102. char *forwarded;
  103. char *obj = *obj_slot;
  104. void *copy;
  105. SGEN_ASSERT (9, current_collection_generation == GENERATION_NURSERY, "calling minor-serial-copy-from-obj from a %d generation collection", current_collection_generation);
  106. HEAVY_STAT (++stat_copy_object_called_nursery);
  107. if (!sgen_ptr_in_nursery (obj)) {
  108. HEAVY_STAT (++stat_nursery_copy_object_failed_from_space);
  109. return;
  110. }
  111. SGEN_LOG (9, "Precise copy of %p from %p", obj, obj_slot);
  112. /*
  113. * Before we can copy the object we must make sure that we are
  114. * allowed to, i.e. that the object not pinned, not already
  115. * forwarded or belongs to the nursery To Space.
  116. */
  117. if ((forwarded = SGEN_OBJECT_IS_FORWARDED (obj))) {
  118. SGEN_ASSERT (9, (*(MonoVTable**)SGEN_LOAD_VTABLE (obj))->gc_descr, "forwarded object %p has no gc descriptor", forwarded);
  119. SGEN_LOG (9, " (already forwarded to %p)", forwarded);
  120. HEAVY_STAT (++stat_nursery_copy_object_failed_forwarded);
  121. *obj_slot = forwarded;
  122. #ifndef SGEN_SIMPLE_NURSERY
  123. if (G_UNLIKELY (sgen_ptr_in_nursery (forwarded) && !sgen_ptr_in_nursery (obj_slot)))
  124. sgen_add_to_global_remset (obj_slot, forwarded);
  125. #endif
  126. return;
  127. }
  128. if (G_UNLIKELY (SGEN_OBJECT_IS_PINNED (obj))) {
  129. SGEN_ASSERT (9, ((MonoVTable*)SGEN_LOAD_VTABLE(obj))->gc_descr, "pinned object %p has no gc descriptor", obj);
  130. SGEN_LOG (9, " (pinned, no change)");
  131. HEAVY_STAT (++stat_nursery_copy_object_failed_pinned);
  132. if (!sgen_ptr_in_nursery (obj_slot))
  133. sgen_add_to_global_remset (obj_slot, obj);
  134. return;
  135. }
  136. #ifndef SGEN_SIMPLE_NURSERY
  137. if (sgen_nursery_is_to_space (obj)) {
  138. SGEN_ASSERT (9, ((MonoVTable*)SGEN_LOAD_VTABLE(obj))->gc_descr, "to space object %p has no gc descriptor", obj);
  139. SGEN_LOG (9, " (tospace, no change)");
  140. HEAVY_STAT (++stat_nursery_copy_object_failed_to_space);
  141. /*
  142. * FIXME:
  143. *
  144. * The card table scanning code sometimes clears cards
  145. * that have just been set for a global remset. In
  146. * the split nursery the following situation can
  147. * occur:
  148. *
  149. * Let's say object A starts in card C but continues
  150. * into C+1. Within A, at offset O there's a
  151. * reference to a new nursery object X. A+O is in
  152. * card C+1. Now card C is scanned, and as part of
  153. * it, object A. The reference at A+O is processed by
  154. * copying X into nursery to-space at Y. Since it's
  155. * still in the nursery, a global remset must be added
  156. * for A+O, so card C+1 is marked. Now, however, card
  157. * C+1 is scanned, which means that it's cleared
  158. * first. This wouldn't be terribly bad if reference
  159. * A+O were re-scanned and the global remset re-added,
  160. * but since the reference points to to-space, that
  161. * doesn't happen, and C+1 remains cleared: the remset
  162. * is lost.
  163. *
  164. * There's at least two ways to fix this. The easy
  165. * one is to re-add the remset on the re-scan. This
  166. * is that - the following two lines of code.
  167. *
  168. * The proper solution appears to be to first make a
  169. * copy of the cards before scanning a block, then to
  170. * clear all the cards and scan from the copy, so no
  171. * remsets will be overwritten. Scanning objects at
  172. * most once would be the icing on the cake.
  173. */
  174. if (!sgen_ptr_in_nursery (obj_slot))
  175. sgen_add_to_global_remset (obj_slot, obj);
  176. return;
  177. }
  178. #endif
  179. HEAVY_STAT (++stat_objects_copied_nursery);
  180. copy = copy_object_no_checks (obj, queue);
  181. *obj_slot = copy;
  182. #ifndef SGEN_SIMPLE_NURSERY
  183. if (G_UNLIKELY (sgen_ptr_in_nursery (copy) && !sgen_ptr_in_nursery (obj_slot)))
  184. sgen_add_to_global_remset (obj_slot, copy);
  185. #else
  186. /* copy_object_no_checks () can return obj on OOM */
  187. if (G_UNLIKELY (obj == copy)) {
  188. if (G_UNLIKELY (sgen_ptr_in_nursery (copy) && !sgen_ptr_in_nursery (obj_slot)))
  189. sgen_add_to_global_remset (obj_slot, copy);
  190. }
  191. #endif
  192. }
  193. static void
  194. PARALLEL_COPY_OBJECT (void **obj_slot, SgenGrayQueue *queue)
  195. {
  196. char *obj = *obj_slot;
  197. mword vtable_word, objsize;
  198. MonoVTable *vt;
  199. void *destination;
  200. gboolean has_references;
  201. SGEN_ASSERT (9, current_collection_generation == GENERATION_NURSERY, "calling minor-par-copy from a %d generation collection", current_collection_generation);
  202. HEAVY_STAT (++stat_copy_object_called_nursery);
  203. if (!sgen_ptr_in_nursery (obj)) {
  204. HEAVY_STAT (++stat_nursery_copy_object_failed_from_space);
  205. return;
  206. }
  207. vtable_word = *(mword*)obj;
  208. vt = (MonoVTable*)(vtable_word & ~SGEN_VTABLE_BITS_MASK);
  209. /*
  210. * Before we can copy the object we must make sure that we are
  211. * allowed to, i.e. that the object not pinned, not already
  212. * forwarded and not in the nursery To Space.
  213. */
  214. if (vtable_word & SGEN_FORWARDED_BIT) {
  215. HEAVY_STAT (++stat_nursery_copy_object_failed_forwarded);
  216. *obj_slot = vt;
  217. return;
  218. }
  219. if (vtable_word & SGEN_PINNED_BIT) {
  220. HEAVY_STAT (++stat_nursery_copy_object_failed_pinned);
  221. return;
  222. }
  223. if (sgen_nursery_is_to_space (obj)) {
  224. HEAVY_STAT (++stat_nursery_copy_object_failed_to_space);
  225. return;
  226. }
  227. HEAVY_STAT (++stat_objects_copied_nursery);
  228. objsize = SGEN_ALIGN_UP (sgen_par_object_get_size (vt, (MonoObject*)obj));
  229. has_references = SGEN_VTABLE_HAS_REFERENCES (vt);
  230. destination = COLLECTOR_PARALLEL_ALLOC_FOR_PROMOTION (vt, obj, objsize, has_references);
  231. if (G_UNLIKELY (!destination)) {
  232. sgen_parallel_pin_or_update (obj_slot, obj, vt, queue);
  233. return;
  234. }
  235. *(MonoVTable**)destination = vt;
  236. if (SGEN_CAS_PTR ((void*)obj, (void*)((mword)destination | SGEN_FORWARDED_BIT), vt) == vt) {
  237. par_copy_object_no_checks (destination, vt, obj, objsize, has_references ? queue : NULL);
  238. obj = destination;
  239. *obj_slot = obj;
  240. } else {
  241. /* FIXME: unify with code in major_copy_or_mark_object() */
  242. /* FIXME: Give destination back to the allocator. */
  243. /*The major collector only needs the first word zeroed and nursery requires all bits to be. */
  244. if (!sgen_ptr_in_nursery (destination))
  245. *(void**)destination = NULL;
  246. else
  247. memset (destination, 0, objsize);
  248. vtable_word = *(mword*)obj;
  249. g_assert (vtable_word & SGEN_FORWARDED_BIT);
  250. obj = (void*)(vtable_word & ~SGEN_VTABLE_BITS_MASK);
  251. *obj_slot = obj;
  252. HEAVY_STAT (++stat_slots_allocated_in_vain);
  253. }
  254. }
  255. #define FILL_MINOR_COLLECTOR_COPY_OBJECT(collector) do { \
  256. (collector)->serial_ops.copy_or_mark_object = SERIAL_COPY_OBJECT; \
  257. (collector)->parallel_ops.copy_or_mark_object = PARALLEL_COPY_OBJECT; \
  258. } while (0)