Merge pull request #392 from baulig/master
[mono.git] / mono / metadata / sgen-pinning.c
index bd28cdfd0b4e5403c057af5ee7ab722620fe950d..68e8cf46e8745edbfe1dbd738d325f46d79f1039 100644 (file)
  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  */
-#define PIN_STAGING_AREA_SIZE  1024
 
-static void* pin_staging_area [PIN_STAGING_AREA_SIZE];
-static int pin_staging_area_index;
+#include "config.h"
+#ifdef HAVE_SGEN_GC
+
+#include "metadata/sgen-gc.h"
+#include "metadata/sgen-pinning.h"
 
 static void** pin_queue;
 static int pin_queue_size = 0;
 static int next_pin_slot = 0;
+static int last_num_pinned = 0;
 
-static void
-init_pinning (void)
+#define PIN_HASH_SIZE 1024
+static void *pin_hash_filter [PIN_HASH_SIZE];
+
+void
+sgen_init_pinning (void)
+{
+       memset (pin_hash_filter, 0, sizeof (pin_hash_filter));
+}
+
+void
+sgen_finish_pinning (void)
 {
-       pin_staging_area_index = 0;
+       last_num_pinned = next_pin_slot;
+       next_pin_slot = 0;
 }
 
 static void
 realloc_pin_queue (void)
 {
        int new_size = pin_queue_size? pin_queue_size + pin_queue_size/2: 1024;
-       void **new_pin = mono_sgen_alloc_internal_dynamic (sizeof (void*) * new_size, INTERNAL_MEM_PIN_QUEUE);
+       void **new_pin = sgen_alloc_internal_dynamic (sizeof (void*) * new_size, INTERNAL_MEM_PIN_QUEUE);
        memcpy (new_pin, pin_queue, sizeof (void*) * next_pin_slot);
-       mono_sgen_free_internal_dynamic (pin_queue, sizeof (void*) * pin_queue_size, INTERNAL_MEM_PIN_QUEUE);
+       sgen_free_internal_dynamic (pin_queue, sizeof (void*) * pin_queue_size, INTERNAL_MEM_PIN_QUEUE);
        pin_queue = new_pin;
        pin_queue_size = new_size;
        DEBUG (4, fprintf (gc_debug_file, "Reallocated pin queue to size: %d\n", new_size));
 }
 
-static void
-evacuate_pin_staging_area (void)
+void
+sgen_pin_stage_ptr (void *ptr)
 {
-       int i;
-
-       g_assert (pin_staging_area_index >= 0 && pin_staging_area_index <= PIN_STAGING_AREA_SIZE);
-
-       if (pin_staging_area_index == 0)
+       /*very simple multiplicative hash function, tons better than simple and'ng */ 
+       int hash_idx = ((mword)ptr * 1737350767) & (PIN_HASH_SIZE - 1);
+       if (pin_hash_filter [hash_idx] == ptr)
                return;
 
-       /*
-        * The pinning addresses might come from undefined memory, this is normal. Since they
-        * are used in lots of functions, we make the memory defined here instead of having
-        * to add a supression for those functions.
-        */
-       VALGRIND_MAKE_MEM_DEFINED (pin_staging_area, pin_staging_area_index * sizeof (void*));
-
-       sort_addresses (pin_staging_area, pin_staging_area_index);
+       pin_hash_filter [hash_idx] = ptr;
 
-       while (next_pin_slot + pin_staging_area_index > pin_queue_size)
+       if (next_pin_slot >= pin_queue_size)
                realloc_pin_queue ();
 
-       pin_queue [next_pin_slot++] = pin_staging_area [0];
-       for (i = 1; i < pin_staging_area_index; ++i) {
-               void *p = pin_staging_area [i];
-               if (p != pin_queue [next_pin_slot - 1])
-                       pin_queue [next_pin_slot++] = p;
-       }
-
-       g_assert (next_pin_slot <= pin_queue_size);
-
-       pin_staging_area_index = 0;
-}
-
-static void
-pin_stage_ptr (void *ptr)
-{
-       if (pin_staging_area_index >= PIN_STAGING_AREA_SIZE)
-               evacuate_pin_staging_area ();
-
-       pin_staging_area [pin_staging_area_index++] = ptr;
+       pin_queue [next_pin_slot++] = ptr;
 }
 
 static int
@@ -107,7 +93,7 @@ optimized_pin_queue_search (void *addr)
 }
 
 void**
-mono_sgen_find_optimized_pin_queue_area (void *start, void *end, int *num)
+sgen_find_optimized_pin_queue_area (void *start, void *end, int *num)
 {
        int first, last;
        first = optimized_pin_queue_search (start);
@@ -119,20 +105,37 @@ mono_sgen_find_optimized_pin_queue_area (void *start, void *end, int *num)
 }
 
 void
-mono_sgen_find_section_pin_queue_start_end (GCMemSection *section)
+sgen_find_section_pin_queue_start_end (GCMemSection *section)
 {
        DEBUG (6, fprintf (gc_debug_file, "Pinning from section %p (%p-%p)\n", section, section->data, section->end_data));
-       section->pin_queue_start = mono_sgen_find_optimized_pin_queue_area (section->data, section->end_data, &section->pin_queue_num_entries);
+       section->pin_queue_start = sgen_find_optimized_pin_queue_area (section->data, section->end_data, &section->pin_queue_num_entries);
        DEBUG (6, fprintf (gc_debug_file, "Found %d pinning addresses in section %p\n", section->pin_queue_num_entries, section));
 }
 
-static void
-mono_sgen_pin_queue_clear_discarded_entries (GCMemSection *section, int max_pin_slot)
+/*This will setup the given section for the while pin queue. */
+void
+sgen_pinning_setup_section (GCMemSection *section)
+{
+       section->pin_queue_start = pin_queue;
+       section->pin_queue_num_entries = next_pin_slot;
+}
+
+void
+sgen_pinning_trim_queue_to_section (GCMemSection *section)
+{
+       next_pin_slot = section->pin_queue_num_entries;
+}
+
+void
+sgen_pin_queue_clear_discarded_entries (GCMemSection *section, int max_pin_slot)
 {
        void **start = section->pin_queue_start + section->pin_queue_num_entries;
        void **end = pin_queue + max_pin_slot;
        void *addr;
 
+       if (!start)
+               return;
+
        for (; start < end; ++start) {
                addr = *start;
                if ((char*)addr < section->data || (char*)addr > section->end_data)
@@ -140,3 +143,59 @@ mono_sgen_pin_queue_clear_discarded_entries (GCMemSection *section, int max_pin_
                *start = NULL;
        }
 }
+
+static G_GNUC_UNUSED void
+print_nursery_gaps (void* start_nursery, void *end_nursery)
+{
+       int i;
+       gpointer first = start_nursery;
+       gpointer next;
+       for (i = 0; i < next_pin_slot; ++i) {
+               next = pin_queue [i];
+               fprintf (gc_debug_file, "Nursery range: %p-%p, size: %td\n", first, next, (char*)next-(char*)first);
+               first = next;
+       }
+       next = end_nursery;
+       fprintf (gc_debug_file, "Nursery range: %p-%p, size: %td\n", first, next, (char*)next-(char*)first);
+}
+
+/* reduce the info in the pin queue, removing duplicate pointers and sorting them */
+void
+sgen_optimize_pin_queue (int start_slot)
+{
+       void **start, **cur, **end;
+       /* sort and uniq pin_queue: we just sort and we let the rest discard multiple values */
+       /* it may be better to keep ranges of pinned memory instead of individually pinning objects */
+       DEBUG (5, fprintf (gc_debug_file, "Sorting pin queue, size: %d\n", next_pin_slot));
+       if ((next_pin_slot - start_slot) > 1)
+               sgen_sort_addresses (pin_queue + start_slot, next_pin_slot - start_slot);
+       start = cur = pin_queue + start_slot;
+       end = pin_queue + next_pin_slot;
+       while (cur < end) {
+               *start = *cur++;
+               while (*start == *cur && cur < end)
+                       cur++;
+               start++;
+       };
+       next_pin_slot = start - pin_queue;
+       DEBUG (5, fprintf (gc_debug_file, "Pin queue reduced to size: %d\n", next_pin_slot));
+       //DEBUG (6, print_nursery_gaps (start_nursery, end_nursery));   
+}
+
+int
+sgen_get_pinned_count (void)
+{
+       return next_pin_slot;
+}
+
+void
+sgen_dump_pin_queue (void)
+{
+       int i;
+
+       for (i = 0; i < last_num_pinned; ++i) {
+               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])));
+       }       
+}
+
+#endif /* HAVE_SGEN_GC */