2 * sgen-pinning.c: The pin queue.
4 * Copyright 2001-2003 Ximian, Inc
5 * Copyright 2003-2010 Novell, Inc.
6 * Copyright (C) 2012 Xamarin Inc
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License 2.0 as published by the Free Software Foundation;
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License 2.0 along with this library; if not, write to the Free
19 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #include "metadata/sgen-gc.h"
26 #include "metadata/sgen-pinning.h"
28 static void** pin_queue;
29 static int pin_queue_size = 0;
30 static int next_pin_slot = 0;
31 static int last_num_pinned = 0;
33 #define PIN_HASH_SIZE 1024
34 static void *pin_hash_filter [PIN_HASH_SIZE];
37 sgen_init_pinning (void)
39 memset (pin_hash_filter, 0, sizeof (pin_hash_filter));
43 sgen_finish_pinning (void)
45 last_num_pinned = next_pin_slot;
50 realloc_pin_queue (void)
52 int new_size = pin_queue_size? pin_queue_size + pin_queue_size/2: 1024;
53 void **new_pin = sgen_alloc_internal_dynamic (sizeof (void*) * new_size, INTERNAL_MEM_PIN_QUEUE, TRUE);
54 memcpy (new_pin, pin_queue, sizeof (void*) * next_pin_slot);
55 sgen_free_internal_dynamic (pin_queue, sizeof (void*) * pin_queue_size, INTERNAL_MEM_PIN_QUEUE);
57 pin_queue_size = new_size;
58 SGEN_LOG (4, "Reallocated pin queue to size: %d", new_size);
62 sgen_pin_stage_ptr (void *ptr)
64 /*very simple multiplicative hash function, tons better than simple and'ng */
65 int hash_idx = ((mword)ptr * 1737350767) & (PIN_HASH_SIZE - 1);
66 if (pin_hash_filter [hash_idx] == ptr)
69 pin_hash_filter [hash_idx] = ptr;
71 if (next_pin_slot >= pin_queue_size)
74 pin_queue [next_pin_slot++] = ptr;
78 optimized_pin_queue_search (void *addr)
80 int first = 0, last = next_pin_slot;
81 while (first < last) {
82 int middle = first + ((last - first) >> 1);
83 if (addr <= pin_queue [middle])
88 g_assert (first == last);
93 sgen_find_optimized_pin_queue_area (void *start, void *end, int *num)
96 first = optimized_pin_queue_search (start);
97 last = optimized_pin_queue_search (end);
101 return pin_queue + first;
105 sgen_find_section_pin_queue_start_end (GCMemSection *section)
107 SGEN_LOG (6, "Pinning from section %p (%p-%p)", section, section->data, section->end_data);
108 section->pin_queue_start = sgen_find_optimized_pin_queue_area (section->data, section->end_data, §ion->pin_queue_num_entries);
109 SGEN_LOG (6, "Found %d pinning addresses in section %p", section->pin_queue_num_entries, section);
112 /*This will setup the given section for the while pin queue. */
114 sgen_pinning_setup_section (GCMemSection *section)
116 section->pin_queue_start = pin_queue;
117 section->pin_queue_num_entries = next_pin_slot;
121 sgen_pinning_trim_queue_to_section (GCMemSection *section)
123 next_pin_slot = section->pin_queue_num_entries;
127 sgen_pin_queue_clear_discarded_entries (GCMemSection *section, int max_pin_slot)
129 void **start = section->pin_queue_start + section->pin_queue_num_entries;
130 void **end = pin_queue + max_pin_slot;
136 for (; start < end; ++start) {
138 if ((char*)addr < section->data || (char*)addr > section->end_data)
144 /* reduce the info in the pin queue, removing duplicate pointers and sorting them */
146 sgen_optimize_pin_queue (int start_slot)
148 void **start, **cur, **end;
149 /* sort and uniq pin_queue: we just sort and we let the rest discard multiple values */
150 /* it may be better to keep ranges of pinned memory instead of individually pinning objects */
151 SGEN_LOG (5, "Sorting pin queue, size: %d", next_pin_slot);
152 if ((next_pin_slot - start_slot) > 1)
153 sgen_sort_addresses (pin_queue + start_slot, next_pin_slot - start_slot);
154 start = cur = pin_queue + start_slot;
155 end = pin_queue + next_pin_slot;
158 while (*start == *cur && cur < end)
162 next_pin_slot = start - pin_queue;
163 SGEN_LOG (5, "Pin queue reduced to size: %d", next_pin_slot);
167 sgen_get_pinned_count (void)
169 return next_pin_slot;
173 sgen_dump_pin_queue (void)
177 for (i = 0; i < last_num_pinned; ++i) {
178 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 #endif /* HAVE_SGEN_GC */