[System] Process.WaitForExit now triggers event Exited.
[mono.git] / mono / metadata / sgen-marksweep-drain-gray-stack.h
1 /*
2  * sgen-marksweep-drain-gray-stack.h: The copy/mark and gray stack
3  *     draining functions of the M&S major collector.
4  *
5  * Copyright (C) 2014 Xamarin Inc
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License 2.0 as published by the Free Software Foundation;
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License 2.0 along with this library; if not, write to the Free
18  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  */
20
21 /*
22  * COPY_OR_MARK_FUNCTION_NAME must be defined to be the function name of the copy/mark
23  * function.
24  *
25  * SCAN_OBJECT_FUNCTION_NAME must be defined to be the function name of the object scanning
26  * function.
27  *
28  * DRAIN_GRAY_STACK_FUNCTION_NAME must be defined to be the function name of the gray stack
29  * draining function.
30  *
31  * Define COPY_OR_MARK_WITH_EVACUATION to support evacuation.
32  */
33
34 /* Returns whether the object is still in the nursery. */
35 static inline MONO_ALWAYS_INLINE gboolean
36 COPY_OR_MARK_FUNCTION_NAME (void **ptr, void *obj, SgenGrayQueue *queue)
37 {
38         MSBlockInfo *block;
39
40 #ifdef HEAVY_STATISTICS
41         ++stat_optimized_copy;
42         {
43                 char *forwarded;
44                 mword desc;
45                 if ((forwarded = SGEN_OBJECT_IS_FORWARDED (obj)))
46                         desc = sgen_obj_get_descriptor_safe (forwarded);
47                 else
48                         desc = sgen_obj_get_descriptor_safe (obj);
49
50                 sgen_descriptor_count_copied_object (desc);
51         }
52 #endif
53
54         SGEN_ASSERT (9, obj, "null object from pointer %p", ptr);
55         SGEN_ASSERT (9, current_collection_generation == GENERATION_OLD, "old gen parallel allocator called from a %d collection", current_collection_generation);
56
57         if (sgen_ptr_in_nursery (obj)) {
58                 int word, bit;
59                 char *forwarded, *old_obj;
60                 mword vtable_word = *(mword*)obj;
61
62                 HEAVY_STAT (++stat_optimized_copy_nursery);
63
64 #if SGEN_MAX_DEBUG_LEVEL >= 9
65                 if (sgen_nursery_is_to_space (obj))
66                         SGEN_ASSERT (9, !SGEN_VTABLE_IS_PINNED (vtable_word) && !SGEN_VTABLE_IS_FORWARDED (vtable_word), "To-space object can't be pinned or forwarded.");
67 #endif
68
69                 if (SGEN_VTABLE_IS_PINNED (vtable_word)) {
70                         SGEN_ASSERT (9, !SGEN_VTABLE_IS_FORWARDED (vtable_word), "Cannot be both pinned and forwarded.");
71                         HEAVY_STAT (++stat_optimized_copy_nursery_pinned);
72                         return TRUE;
73                 }
74                 if ((forwarded = SGEN_VTABLE_IS_FORWARDED (vtable_word))) {
75                         HEAVY_STAT (++stat_optimized_copy_nursery_forwarded);
76                         SGEN_UPDATE_REFERENCE (ptr, forwarded);
77                         return sgen_ptr_in_nursery (forwarded);
78                 }
79
80                 /* An object in the nursery To Space has already been copied and grayed. Nothing to do. */
81                 if (sgen_nursery_is_to_space (obj))
82                         return TRUE;
83
84 #ifdef COPY_OR_MARK_WITH_EVACUATION
85         do_copy_object:
86 #endif
87                 old_obj = obj;
88                 obj = copy_object_no_checks (obj, queue);
89                 if (G_UNLIKELY (old_obj == obj)) {
90                         /*
91                          * If we fail to evacuate an object we just stop doing it for a
92                          * given block size as all other will surely fail too.
93                          */
94                         /* FIXME: test this case somehow. */
95                         if (!sgen_ptr_in_nursery (obj)) {
96                                 int size_index;
97                                 block = MS_BLOCK_FOR_OBJ (obj);
98                                 size_index = block->obj_size_index;
99                                 evacuate_block_obj_sizes [size_index] = FALSE;
100                                 MS_MARK_OBJECT_AND_ENQUEUE (obj, sgen_obj_get_descriptor (obj), block, queue);
101                                 return FALSE;
102                         }
103                         return TRUE;
104                 }
105                 HEAVY_STAT (++stat_objects_copied_major);
106                 SGEN_UPDATE_REFERENCE (ptr, obj);
107
108                 if (sgen_ptr_in_nursery (obj))
109                         return TRUE;
110
111                 /*
112                  * FIXME: See comment for copy_object_no_checks().  If
113                  * we have that, we can let the allocation function
114                  * give us the block info, too, and we won't have to
115                  * re-fetch it.
116                  *
117                  * FIXME (2): We should rework this to avoid all those nursery checks.
118                  */
119                 /*
120                  * For the split nursery allocator the object might
121                  * still be in the nursery despite having being
122                  * promoted, in which case we can't mark it.
123                  */
124                 block = MS_BLOCK_FOR_OBJ (obj);
125                 MS_CALC_MARK_BIT (word, bit, obj);
126                 SGEN_ASSERT (9, !MS_MARK_BIT (block, word, bit), "object %p already marked", obj);
127                 MS_SET_MARK_BIT (block, word, bit);
128                 binary_protocol_mark (obj, (gpointer)LOAD_VTABLE (obj), sgen_safe_object_get_size ((MonoObject*)obj));
129
130                 return FALSE;
131         } else {
132                 mword vtable_word = *(mword*)obj;
133                 mword desc;
134                 int type;
135
136                 HEAVY_STAT (++stat_optimized_copy_major);
137
138 #ifdef COPY_OR_MARK_WITH_EVACUATION
139                 {
140                         char *forwarded;
141                         if ((forwarded = SGEN_VTABLE_IS_FORWARDED (vtable_word))) {
142                                 HEAVY_STAT (++stat_optimized_copy_major_forwarded);
143                                 SGEN_UPDATE_REFERENCE (ptr, forwarded);
144                                 SGEN_ASSERT (9, !sgen_ptr_in_nursery (forwarded), "Cannot be forwarded to nursery.");
145                                 return FALSE;
146                         }
147                 }
148 #endif
149
150                 SGEN_ASSERT (9, !SGEN_VTABLE_IS_PINNED (vtable_word), "Pinned object in non-pinned block?");
151
152                 desc = sgen_vtable_get_descriptor ((MonoVTable*)vtable_word);
153                 type = desc & DESC_TYPE_MASK;
154
155                 if (type <= DESC_TYPE_MAX_SMALL_OBJ || SGEN_ALIGN_UP (sgen_safe_object_get_size ((MonoObject*)obj)) <= SGEN_MAX_SMALL_OBJ_SIZE) {
156 #ifdef HEAVY_STATISTICS
157                         if (type <= DESC_TYPE_MAX_SMALL_OBJ)
158                                 ++stat_optimized_copy_major_small_fast;
159                         else
160                                 ++stat_optimized_copy_major_small_slow;
161 #endif
162
163                         block = MS_BLOCK_FOR_OBJ (obj);
164
165 #ifdef COPY_OR_MARK_WITH_EVACUATION
166                         {
167                                 int size_index = block->obj_size_index;
168
169                                 if (evacuate_block_obj_sizes [size_index] && !block->has_pinned) {
170                                         HEAVY_STAT (++stat_optimized_copy_major_small_evacuate);
171                                         if (block->is_to_space)
172                                                 return FALSE;
173                                         goto do_copy_object;
174                                 }
175                         }
176 #endif
177
178                         MS_MARK_OBJECT_AND_ENQUEUE (obj, desc, block, queue);
179                 } else {
180                         HEAVY_STAT (++stat_optimized_copy_major_large);
181
182                         if (sgen_los_object_is_pinned (obj))
183                                 return FALSE;
184                         binary_protocol_pin (obj, (gpointer)SGEN_LOAD_VTABLE (obj), sgen_safe_object_get_size ((MonoObject*)obj));
185
186                         sgen_los_pin_object (obj);
187                         if (SGEN_OBJECT_HAS_REFERENCES (obj))
188                                 GRAY_OBJECT_ENQUEUE (queue, obj, sgen_obj_get_descriptor (obj));
189                 }
190                 return FALSE;
191         }
192         SGEN_ASSERT (0, FALSE, "How is this happening?");
193         return FALSE;
194 }
195
196 static void
197 SCAN_OBJECT_FUNCTION_NAME (char *obj, mword desc, SgenGrayQueue *queue)
198 {
199         char *start = obj;
200
201 #ifdef HEAVY_STATISTICS
202         ++stat_optimized_major_scan;
203         if (!sgen_gc_descr_has_references (desc))
204                 ++stat_optimized_major_scan_no_refs;
205         sgen_descriptor_count_scanned_object (desc);
206 #endif
207 #ifdef SGEN_HEAVY_BINARY_PROTOCOL
208         add_scanned_object (start);
209 #endif
210
211         /* Now scan the object. */
212
213 #undef HANDLE_PTR
214 #define HANDLE_PTR(ptr,obj)     do {                                    \
215                 void *__old = *(ptr);                                   \
216                 binary_protocol_scan_process_reference ((obj), (ptr), __old); \
217                 if (__old) {                                            \
218                         gboolean __still_in_nursery = COPY_OR_MARK_FUNCTION_NAME ((ptr), __old, queue); \
219                         if (G_UNLIKELY (__still_in_nursery && !sgen_ptr_in_nursery ((ptr)) && !SGEN_OBJECT_IS_CEMENTED (*(ptr)))) { \
220                                 void *__copy = *(ptr);                  \
221                                 sgen_add_to_global_remset ((ptr), __copy); \
222                         }                                               \
223                 }                                                       \
224         } while (0)
225
226 #define SCAN_OBJECT_PROTOCOL
227 #include "sgen-scan-object.h"
228 }
229
230 static gboolean
231 DRAIN_GRAY_STACK_FUNCTION_NAME (ScanCopyContext ctx)
232 {
233         SgenGrayQueue *queue = ctx.queue;
234
235         SGEN_ASSERT (0, ctx.scan_func == major_scan_object_with_evacuation, "Wrong scan function");
236
237         for (;;) {
238                 char *obj;
239                 mword desc;
240
241                 HEAVY_STAT (++stat_drain_loops);
242
243                 GRAY_OBJECT_DEQUEUE (queue, &obj, &desc);
244                 if (!obj)
245                         return TRUE;
246
247                 SCAN_OBJECT_FUNCTION_NAME (obj, desc, ctx.queue);
248         }
249 }
250
251 #undef COPY_OR_MARK_FUNCTION_NAME
252 #undef COPY_OR_MARK_WITH_EVACUATION
253 #undef SCAN_OBJECT_FUNCTION_NAME
254 #undef DRAIN_GRAY_STACK_FUNCTION_NAME