Rework pinning code to isolate it into a proper module. One less include hack.
[mono.git] / mono / metadata / sgen-pinning.c
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 #include "config.h"
26 #ifdef HAVE_SGEN_GC
27
28 #include "metadata/sgen-gc.h"
29 #include "metadata/sgen-pinning.h"
30
31 static void** pin_queue;
32 static int pin_queue_size = 0;
33 static int next_pin_slot = 0;
34 static int last_num_pinned = 0;
35
36 #define PIN_HASH_SIZE 1024
37 static void *pin_hash_filter [PIN_HASH_SIZE];
38
39 void
40 mono_sgen_init_pinning (void)
41 {
42         memset (pin_hash_filter, 0, sizeof (pin_hash_filter));
43 }
44
45 void
46 mono_sgen_finish_pinning (void)
47 {
48         last_num_pinned = next_pin_slot;
49         next_pin_slot = 0;
50 }
51
52 static void
53 realloc_pin_queue (void)
54 {
55         int new_size = pin_queue_size? pin_queue_size + pin_queue_size/2: 1024;
56         void **new_pin = mono_sgen_alloc_internal_dynamic (sizeof (void*) * new_size, INTERNAL_MEM_PIN_QUEUE);
57         memcpy (new_pin, pin_queue, sizeof (void*) * next_pin_slot);
58         mono_sgen_free_internal_dynamic (pin_queue, sizeof (void*) * pin_queue_size, INTERNAL_MEM_PIN_QUEUE);
59         pin_queue = new_pin;
60         pin_queue_size = new_size;
61         DEBUG (4, fprintf (gc_debug_file, "Reallocated pin queue to size: %d\n", new_size));
62 }
63
64 void
65 mono_sgen_pin_stage_ptr (void *ptr)
66 {
67         /*very simple multiplicative hash function, tons better than simple and'ng */ 
68         int hash_idx = ((mword)ptr * 1737350767) & (PIN_HASH_SIZE - 1);
69         if (pin_hash_filter [hash_idx] == ptr)
70                 return;
71
72         pin_hash_filter [hash_idx] = ptr;
73
74         if (next_pin_slot >= pin_queue_size)
75                 realloc_pin_queue ();
76
77         pin_queue [next_pin_slot++] = ptr;
78 }
79
80 static int
81 optimized_pin_queue_search (void *addr)
82 {
83         int first = 0, last = next_pin_slot;
84         while (first < last) {
85                 int middle = first + ((last - first) >> 1);
86                 if (addr <= pin_queue [middle])
87                         last = middle;
88                 else
89                         first = middle + 1;
90         }
91         g_assert (first == last);
92         return first;
93 }
94
95 void**
96 mono_sgen_find_optimized_pin_queue_area (void *start, void *end, int *num)
97 {
98         int first, last;
99         first = optimized_pin_queue_search (start);
100         last = optimized_pin_queue_search (end);
101         *num = last - first;
102         if (first == last)
103                 return NULL;
104         return pin_queue + first;
105 }
106
107 void
108 mono_sgen_find_section_pin_queue_start_end (GCMemSection *section)
109 {
110         DEBUG (6, fprintf (gc_debug_file, "Pinning from section %p (%p-%p)\n", section, section->data, section->end_data));
111         section->pin_queue_start = mono_sgen_find_optimized_pin_queue_area (section->data, section->end_data, &section->pin_queue_num_entries);
112         DEBUG (6, fprintf (gc_debug_file, "Found %d pinning addresses in section %p\n", section->pin_queue_num_entries, section));
113 }
114
115 /*This will setup the given section for the while pin queue. */
116 void
117 mono_sgen_pinning_setup_section (GCMemSection *section)
118 {
119         section->pin_queue_start = pin_queue;
120         section->pin_queue_num_entries = next_pin_slot;
121 }
122
123
124 void
125 mono_sgen_pin_queue_clear_discarded_entries (GCMemSection *section, int max_pin_slot)
126 {
127         void **start = section->pin_queue_start + section->pin_queue_num_entries;
128         void **end = pin_queue + max_pin_slot;
129         void *addr;
130
131         for (; start < end; ++start) {
132                 addr = *start;
133                 if ((char*)addr < section->data || (char*)addr > section->end_data)
134                         break;
135                 *start = NULL;
136         }
137 }
138
139 static G_GNUC_UNUSED void
140 print_nursery_gaps (void* start_nursery, void *end_nursery)
141 {
142         int i;
143         gpointer first = start_nursery;
144         gpointer next;
145         for (i = 0; i < next_pin_slot; ++i) {
146                 next = pin_queue [i];
147                 fprintf (gc_debug_file, "Nursery range: %p-%p, size: %td\n", first, next, (char*)next-(char*)first);
148                 first = next;
149         }
150         next = end_nursery;
151         fprintf (gc_debug_file, "Nursery range: %p-%p, size: %td\n", first, next, (char*)next-(char*)first);
152 }
153
154 /* reduce the info in the pin queue, removing duplicate pointers and sorting them */
155 void
156 mono_sgen_optimize_pin_queue (int start_slot)
157 {
158         void **start, **cur, **end;
159         /* sort and uniq pin_queue: we just sort and we let the rest discard multiple values */
160         /* it may be better to keep ranges of pinned memory instead of individually pinning objects */
161         DEBUG (5, fprintf (gc_debug_file, "Sorting pin queue, size: %d\n", next_pin_slot));
162         if ((next_pin_slot - start_slot) > 1)
163                 mono_sgen_sort_addresses (pin_queue + start_slot, next_pin_slot - start_slot);
164         start = cur = pin_queue + start_slot;
165         end = pin_queue + next_pin_slot;
166         while (cur < end) {
167                 *start = *cur++;
168                 while (*start == *cur && cur < end)
169                         cur++;
170                 start++;
171         };
172         next_pin_slot = start - pin_queue;
173         DEBUG (5, fprintf (gc_debug_file, "Pin queue reduced to size: %d\n", next_pin_slot));
174         //DEBUG (6, print_nursery_gaps (start_nursery, end_nursery));   
175 }
176
177 int
178 mono_sgen_get_pinned_count (void)
179 {
180         return next_pin_slot;
181 }
182
183 void
184 mono_sgen_dump_pin_queue (void)
185 {
186         int i;
187
188         for (i = 0; i < last_num_pinned; ++i) {
189                 DEBUG (3, fprintf (gc_debug_file, "Bastard pinning obj %p (%s), size: %d\n", pin_queue [i], mono_sgen_safe_name (pin_queue [i]), mono_sgen_safe_object_get_size (pin_queue [i])));
190         }       
191 }
192
193 #endif /* HAVE_SGEN_GC */