2 * Copyright 2001-2003 Ximian, Inc
3 * Copyright 2003-2010 Novell, Inc.
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:
13 * The above copyright notice and this permission notice shall be
14 * included in all copies or substantial portions of the Software.
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.
28 #include "metadata/sgen-gc.h"
29 #include "metadata/sgen-pinning.h"
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;
36 #define PIN_HASH_SIZE 1024
37 static void *pin_hash_filter [PIN_HASH_SIZE];
40 sgen_init_pinning (void)
42 memset (pin_hash_filter, 0, sizeof (pin_hash_filter));
46 sgen_finish_pinning (void)
48 last_num_pinned = next_pin_slot;
53 realloc_pin_queue (void)
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);
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);
60 pin_queue_size = new_size;
61 DEBUG (4, fprintf (gc_debug_file, "Reallocated pin queue to size: %d\n", new_size));
65 sgen_pin_stage_ptr (void *ptr)
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)
72 pin_hash_filter [hash_idx] = ptr;
74 if (next_pin_slot >= pin_queue_size)
77 pin_queue [next_pin_slot++] = ptr;
81 optimized_pin_queue_search (void *addr)
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])
91 g_assert (first == last);
96 sgen_find_optimized_pin_queue_area (void *start, void *end, int *num)
99 first = optimized_pin_queue_search (start);
100 last = optimized_pin_queue_search (end);
104 return pin_queue + first;
108 sgen_find_section_pin_queue_start_end (GCMemSection *section)
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 = sgen_find_optimized_pin_queue_area (section->data, section->end_data, §ion->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));
115 /*This will setup the given section for the while pin queue. */
117 sgen_pinning_setup_section (GCMemSection *section)
119 section->pin_queue_start = pin_queue;
120 section->pin_queue_num_entries = next_pin_slot;
124 sgen_pinning_trim_queue_to_section (GCMemSection *section)
126 next_pin_slot = section->pin_queue_num_entries;
130 sgen_pin_queue_clear_discarded_entries (GCMemSection *section, int max_pin_slot)
132 void **start = section->pin_queue_start + section->pin_queue_num_entries;
133 void **end = pin_queue + max_pin_slot;
139 for (; start < end; ++start) {
141 if ((char*)addr < section->data || (char*)addr > section->end_data)
147 static G_GNUC_UNUSED void
148 print_nursery_gaps (void* start_nursery, void *end_nursery)
151 gpointer first = start_nursery;
153 for (i = 0; i < next_pin_slot; ++i) {
154 next = pin_queue [i];
155 fprintf (gc_debug_file, "Nursery range: %p-%p, size: %td\n", first, next, (char*)next-(char*)first);
159 fprintf (gc_debug_file, "Nursery range: %p-%p, size: %td\n", first, next, (char*)next-(char*)first);
162 /* reduce the info in the pin queue, removing duplicate pointers and sorting them */
164 sgen_optimize_pin_queue (int start_slot)
166 void **start, **cur, **end;
167 /* sort and uniq pin_queue: we just sort and we let the rest discard multiple values */
168 /* it may be better to keep ranges of pinned memory instead of individually pinning objects */
169 DEBUG (5, fprintf (gc_debug_file, "Sorting pin queue, size: %d\n", next_pin_slot));
170 if ((next_pin_slot - start_slot) > 1)
171 sgen_sort_addresses (pin_queue + start_slot, next_pin_slot - start_slot);
172 start = cur = pin_queue + start_slot;
173 end = pin_queue + next_pin_slot;
176 while (*start == *cur && cur < end)
180 next_pin_slot = start - pin_queue;
181 DEBUG (5, fprintf (gc_debug_file, "Pin queue reduced to size: %d\n", next_pin_slot));
182 //DEBUG (6, print_nursery_gaps (start_nursery, end_nursery));
186 sgen_get_pinned_count (void)
188 return next_pin_slot;
192 sgen_dump_pin_queue (void)
196 for (i = 0; i < last_num_pinned; ++i) {
197 DEBUG (3, fprintf (gc_debug_file, "Bastard pinning obj %p (%s), size: %d\n", pin_queue [i], sgen_safe_name (pin_queue [i]), sgen_safe_object_get_size (pin_queue [i])));
201 #endif /* HAVE_SGEN_GC */