Merge pull request #409 from Alkarex/patch-1
[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 sgen_init_pinning (void)
41 {
42         memset (pin_hash_filter, 0, sizeof (pin_hash_filter));
43 }
44
45 void
46 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 = sgen_alloc_internal_dynamic (sizeof (void*) * new_size, INTERNAL_MEM_PIN_QUEUE, TRUE);
57         memcpy (new_pin, pin_queue, sizeof (void*) * next_pin_slot);
58         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         SGEN_LOG (4, "Reallocated pin queue to size: %d", new_size);
62 }
63
64 void
65 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 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 sgen_find_section_pin_queue_start_end (GCMemSection *section)
109 {
110         SGEN_LOG (6, "Pinning from section %p (%p-%p)", section, section->data, section->end_data);
111         section->pin_queue_start = sgen_find_optimized_pin_queue_area (section->data, section->end_data, &section->pin_queue_num_entries);
112         SGEN_LOG (6, "Found %d pinning addresses in section %p", section->pin_queue_num_entries, section);
113 }
114
115 /*This will setup the given section for the while pin queue. */
116 void
117 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 void
124 sgen_pinning_trim_queue_to_section (GCMemSection *section)
125 {
126         next_pin_slot = section->pin_queue_num_entries;
127 }
128
129 void
130 sgen_pin_queue_clear_discarded_entries (GCMemSection *section, int max_pin_slot)
131 {
132         void **start = section->pin_queue_start + section->pin_queue_num_entries;
133         void **end = pin_queue + max_pin_slot;
134         void *addr;
135
136         if (!start)
137                 return;
138
139         for (; start < end; ++start) {
140                 addr = *start;
141                 if ((char*)addr < section->data || (char*)addr > section->end_data)
142                         break;
143                 *start = NULL;
144         }
145 }
146
147 /* reduce the info in the pin queue, removing duplicate pointers and sorting them */
148 void
149 sgen_optimize_pin_queue (int start_slot)
150 {
151         void **start, **cur, **end;
152         /* sort and uniq pin_queue: we just sort and we let the rest discard multiple values */
153         /* it may be better to keep ranges of pinned memory instead of individually pinning objects */
154         SGEN_LOG (5, "Sorting pin queue, size: %d", next_pin_slot);
155         if ((next_pin_slot - start_slot) > 1)
156                 sgen_sort_addresses (pin_queue + start_slot, next_pin_slot - start_slot);
157         start = cur = pin_queue + start_slot;
158         end = pin_queue + next_pin_slot;
159         while (cur < end) {
160                 *start = *cur++;
161                 while (*start == *cur && cur < end)
162                         cur++;
163                 start++;
164         };
165         next_pin_slot = start - pin_queue;
166         SGEN_LOG (5, "Pin queue reduced to size: %d", next_pin_slot);
167 }
168
169 int
170 sgen_get_pinned_count (void)
171 {
172         return next_pin_slot;
173 }
174
175 void
176 sgen_dump_pin_queue (void)
177 {
178         int i;
179
180         for (i = 0; i < last_num_pinned; ++i) {
181                 SGEN_LOG (3, "Bastard pinning obj %p (%s), size: %d", pin_queue [i], sgen_safe_name (pin_queue [i]), sgen_safe_object_get_size (pin_queue [i]));
182         }       
183 }
184
185 #endif /* HAVE_SGEN_GC */