Reorganize the scan-minor-copy/scan.h header files a bit. Move the nursery copying...
[mono.git] / mono / metadata / sgen-minor-copy-object.h
1 /*
2  * Copyright 2001-2003 Ximian, Inc
3  * Copyright 2003-2010 Novell, Inc.
4  * 
5  * Permission is hereby granted, free of charge, to any person obtaining
6  * a copy of this software and associated documentation files (the
7  * "Software"), to deal in the Software without restriction, including
8  * without limitation the rights to use, copy, modify, merge, publish,
9  * distribute, sublicense, and/or sell copies of the Software, and to
10  * permit persons to whom the Software is furnished to do so, subject to
11  * the following conditions:
12  * 
13  * The above copyright notice and this permission notice shall be
14  * included in all copies or substantial portions of the Software.
15  * 
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  */
24
25 /*
26  * This file defines copy functions for nursery collections.
27  */
28
29 #define collector_pin_object(obj, queue) sgen_pin_object (obj, queue);
30 #define COLLECTOR_SERIAL_ALLOC_FOR_PROMOTION alloc_for_promotion
31 #define COLLECTOR_PARALLEL_ALLOC_FOR_PROMOTION par_alloc_for_promotion
32
33 extern long long stat_nursery_copy_object_failed_to_space; /* from sgen-gc.c */
34
35 #include "sgen-copy-object.h"
36
37 /*
38  * This is how the copying happens from the nursery to the old generation.
39  * We assume that at this time all the pinned objects have been identified and
40  * marked as such.
41  * We run scan_object() for each pinned object so that each referenced
42  * objects if possible are copied. The new gray objects created can have
43  * scan_object() run on them right away, too.
44  * Then we run copy_object() for the precisely tracked roots. At this point
45  * all the roots are either gray or black. We run scan_object() on the gray
46  * objects until no more gray objects are created.
47  * At the end of the process we walk again the pinned list and we unmark
48  * the pinned flag. As we go we also create the list of free space for use
49  * in the next allocation runs.
50  *
51  * We need to remember objects from the old generation that point to the new one
52  * (or just addresses?).
53  *
54  * copy_object could be made into a macro once debugged (use inline for now).
55  */
56
57 #ifdef _MSC_VER
58 static __forceinline void
59 #else
60 static inline void __attribute__((always_inline))
61 #endif
62 SERIAL_COPY_OBJECT (void **obj_slot, SgenGrayQueue *queue) 
63 {
64         char *forwarded;
65         char *obj = *obj_slot;
66
67         DEBUG (9, g_assert (current_collection_generation == GENERATION_NURSERY));
68
69         HEAVY_STAT (++stat_copy_object_called_nursery);
70
71         if (!sgen_ptr_in_nursery (obj)) {
72                 HEAVY_STAT (++stat_nursery_copy_object_failed_from_space);
73                 return;
74         }
75
76         DEBUG (9, fprintf (gc_debug_file, "Precise copy of %p from %p", obj, obj_slot));
77
78         /*
79          * Before we can copy the object we must make sure that we are
80          * allowed to, i.e. that the object not pinned, not already
81          * forwarded or belongs to the nursery To Space.
82          */
83
84         if ((forwarded = SGEN_OBJECT_IS_FORWARDED (obj))) {
85                 DEBUG (9, g_assert ((*(MonoVTable**)SGEN_LOAD_VTABLE(obj))->gc_descr));
86                 DEBUG (9, fprintf (gc_debug_file, " (already forwarded to %p)\n", forwarded));
87                 HEAVY_STAT (++stat_nursery_copy_object_failed_forwarded);
88                 *obj_slot = forwarded;
89                 return;
90         }
91         if (SGEN_OBJECT_IS_PINNED (obj)) {
92                 DEBUG (9, g_assert (((MonoVTable*)SGEN_LOAD_VTABLE(obj))->gc_descr));
93                 DEBUG (9, fprintf (gc_debug_file, " (pinned, no change)\n"));
94                 HEAVY_STAT (++stat_nursery_copy_object_failed_pinned);
95                 return;
96         }
97
98         if (sgen_nursery_is_to_space (obj)) {
99                 DEBUG (9, g_assert (((MonoVTable*)SGEN_LOAD_VTABLE(obj))->gc_descr));
100                 DEBUG (9, fprintf (gc_debug_file, " (tospace, no change)\n"));
101                 HEAVY_STAT (++stat_nursery_copy_object_failed_to_space);                
102                 return;
103         }
104
105         HEAVY_STAT (++stat_objects_copied_nursery);
106
107         *obj_slot = copy_object_no_checks (obj, queue);
108 }
109
110 static void
111 PARALLEL_COPY_OBJECT (void **obj_slot, SgenGrayQueue *queue)
112 {
113         char *obj = *obj_slot;
114         mword vtable_word, objsize;
115         MonoVTable *vt;
116         void *destination;
117         gboolean has_references;
118
119         DEBUG (9, g_assert (current_collection_generation == GENERATION_NURSERY));
120
121         HEAVY_STAT (++stat_copy_object_called_nursery);
122
123         if (!sgen_ptr_in_nursery (obj)) {
124                 HEAVY_STAT (++stat_nursery_copy_object_failed_from_space);
125                 return;
126         }
127
128         vtable_word = *(mword*)obj;
129         vt = (MonoVTable*)(vtable_word & ~SGEN_VTABLE_BITS_MASK);
130
131         /*
132          * Before we can copy the object we must make sure that we are
133          * allowed to, i.e. that the object not pinned, not already
134          * forwarded and not in the nursery To Space.
135          */
136
137         if (vtable_word & SGEN_FORWARDED_BIT) {
138                 HEAVY_STAT (++stat_nursery_copy_object_failed_forwarded);
139                 *obj_slot = vt;
140                 return;
141         }
142         if (vtable_word & SGEN_PINNED_BIT) {
143                 HEAVY_STAT (++stat_nursery_copy_object_failed_pinned);
144                 return;
145         }
146
147         if (sgen_nursery_is_to_space (obj)) {
148                 HEAVY_STAT (++stat_nursery_copy_object_failed_to_space);                
149                 return;
150         }
151
152         HEAVY_STAT (++stat_objects_copied_nursery);
153
154         objsize = SGEN_ALIGN_UP (sgen_par_object_get_size (vt, (MonoObject*)obj));
155         has_references = SGEN_VTABLE_HAS_REFERENCES (vt);
156
157         destination = COLLECTOR_PARALLEL_ALLOC_FOR_PROMOTION (obj, objsize, has_references);
158
159         if (G_UNLIKELY (!destination)) {
160                 sgen_parallel_pin_or_update (obj_slot, obj, vt, queue);
161                 return;
162         }
163
164         *(MonoVTable**)destination = vt;
165
166         if (SGEN_CAS_PTR ((void*)obj, (void*)((mword)destination | SGEN_FORWARDED_BIT), vt) == vt) {
167                 par_copy_object_no_checks (destination, vt, obj, objsize, has_references ? queue : NULL);
168                 obj = destination;
169                 *obj_slot = obj;
170         } else {
171                 /* FIXME: unify with code in major_copy_or_mark_object() */
172
173                 /* FIXME: Give destination back to the allocator. */
174                 /*The major collector only needs the first word zeroed and nursery requires all bits to be. */
175                 if (!sgen_ptr_in_nursery (destination))
176                         *(void**)destination = NULL;
177                 else
178                         memset (destination, 0, objsize);
179
180                 vtable_word = *(mword*)obj;
181                 g_assert (vtable_word & SGEN_FORWARDED_BIT);
182
183                 obj = (void*)(vtable_word & ~SGEN_VTABLE_BITS_MASK);
184
185                 *obj_slot = obj;
186
187                 HEAVY_STAT (++stat_slots_allocated_in_vain);
188         }
189 }
190
191 #define FILL_MINOR_COLLECTOR_COPY_OBJECT(collector)     do {                    \
192                 (collector)->serial_ops.copy_or_mark_object = SERIAL_COPY_OBJECT;                       \
193                 (collector)->parallel_ops.copy_or_mark_object = PARALLEL_COPY_OBJECT;   \
194         } while (0)