#endif
#include <stdio.h>
#include <string.h>
-#include <signal.h>
#include <errno.h>
#include <assert.h>
#ifdef __MACH__
#endif
#include "metadata/sgen-gc.h"
-#include "metadata/metadata-internals.h"
-#include "metadata/class-internals.h"
-#include "metadata/gc-internal.h"
-#include "metadata/object-internals.h"
-#include "metadata/threads.h"
#include "metadata/sgen-cardtable.h"
#include "metadata/sgen-protocol.h"
#include "metadata/sgen-archdep.h"
#include "metadata/sgen-bridge.h"
#include "metadata/sgen-memory-governor.h"
-#include "metadata/mono-gc.h"
-#include "metadata/method-builder.h"
-#include "metadata/profiler-private.h"
-#include "metadata/monitor.h"
-#include "metadata/threadpool-internals.h"
-#include "metadata/mempool-internals.h"
-#include "metadata/marshal.h"
-#include "utils/mono-mmap.h"
-#include "utils/mono-time.h"
-#include "utils/mono-semaphore.h"
-#include "utils/mono-counters.h"
-#include "utils/mono-proclib.h"
-#include "utils/mono-threads.h"
+#include "metadata/sgen-pinning.h"
+#include "metadata/sgen-client.h"
/* Enable it so nursery allocation diagnostic data is collected */
//#define NALLOC_DEBUG 1
#ifdef USER_CONFIG
size_t sgen_nursery_size = (1 << 22);
-#ifdef SGEN_ALIGN_NURSERY
int sgen_nursery_bits = 22;
#endif
-#endif
-char *sgen_space_bitmap MONO_INTERNAL;
-int sgen_space_bitmap_size MONO_INTERNAL;
+char *sgen_space_bitmap;
+size_t sgen_space_bitmap_size;
#ifdef HEAVY_STATISTICS
printf ("------------------------------------DUMP RECORDS----------------------------\n");
for (i = 0; i < next_record; ++i) {
AllocRecord *rec = alloc_records + i;
- printf ("obj [%p, %p] size %zd reason %s seq %d tid %zx\n", rec->address, rec_end (rec), rec->size, get_reason_name (rec), rec->seq, (size_t)rec->tid);
+ printf ("obj [%p, %p] size %d reason %s seq %d tid %x\n", rec->address, rec_end (rec), (int)rec->size, get_reason_name (rec), rec->seq, (size_t)rec->tid);
}
}
hole_size = rec->address - rec_end (prev);
max_hole = MAX (max_hole, hole_size);
}
- printf ("obj [%p, %p] size %zd hole to prev %d reason %s seq %d tid %zx\n", rec->address, rec_end (rec), rec->size, hole_size, get_reason_name (rec), rec->seq, (size_t)rec->tid);
+ printf ("obj [%p, %p] size %d hole to prev %d reason %s seq %d tid %zx\n", rec->address, rec_end (rec), (int)rec->size, hole_size, get_reason_name (rec), rec->seq, (size_t)rec->tid);
prev = rec;
}
printf ("SUMMARY total alloc'd %d holes %d max_hole %d\n", total, holes, max_hole);
* allocating from this dying fragment as it doesn't respect SGEN_MAX_NURSERY_WASTE
* when doing second chance allocation.
*/
- if (sgen_get_nursery_clear_policy () == CLEAR_AT_TLAB_CREATION && claim_remaining_size (frag, end)) {
+ if ((sgen_get_nursery_clear_policy () == CLEAR_AT_TLAB_CREATION || sgen_get_nursery_clear_policy () == CLEAR_AT_TLAB_CREATION_DEBUG) && claim_remaining_size (frag, end)) {
sgen_clear_range (end, frag->fragment_end);
HEAVY_STAT (InterlockedExchangeAdd (&stat_wasted_bytes_trailer, frag->fragment_end - end));
#ifdef NALLOC_DEBUG
/*frag->next read must happen before the first CAS*/
mono_memory_write_barrier ();
- /*Fail if the next done is removed concurrently and its CAS wins */
+ /*Fail if the next node is removed concurrently and its CAS wins */
if (InterlockedCompareExchangePointer ((volatile gpointer*)&frag->next, mask (next, 1), next) != next) {
continue;
}
mono_memory_write_barrier ();
/* Fail if the previous node was deleted and its CAS wins */
- if (InterlockedCompareExchangePointer ((volatile gpointer*)prev_ptr, next, frag) != frag) {
+ if (InterlockedCompareExchangePointer ((volatile gpointer*)prev_ptr, unmask (next), frag) != frag) {
prev_ptr = find_previous_pointer_fragment (allocator, frag);
continue;
}
for (frag = unmask (allocator->alloc_head); unmask (frag); frag = unmask (frag->next)) {
HEAVY_STAT (InterlockedIncrement (&stat_alloc_iterations));
- if (size <= (frag->fragment_end - frag->fragment_next)) {
+ if (size <= (size_t)(frag->fragment_end - frag->fragment_next)) {
void *p = par_alloc_from_fragment (allocator, frag, size);
if (!p) {
HEAVY_STAT (InterlockedIncrement (&stat_alloc_retries));
#endif
for (frag = unmask (allocator->alloc_head); frag; frag = unmask (frag->next)) {
- int frag_size = frag->fragment_end - frag->fragment_next;
+ size_t frag_size = frag->fragment_end - frag->fragment_next;
HEAVY_STAT (InterlockedIncrement (&stat_alloc_range_iterations));
if (min_frag) {
void *p;
- int frag_size;
+ size_t frag_size;
frag_size = min_frag->fragment_end - min_frag->fragment_next;
if (frag_size < minimum_size)
void
sgen_clear_nursery_fragments (void)
{
- if (sgen_get_nursery_clear_policy () == CLEAR_AT_TLAB_CREATION) {
+ if (sgen_get_nursery_clear_policy () == CLEAR_AT_TLAB_CREATION || sgen_get_nursery_clear_policy () == CLEAR_AT_TLAB_CREATION_DEBUG) {
sgen_clear_allocator_fragments (&mutator_allocator);
sgen_minor_collector.clear_fragments ();
}
void
sgen_clear_range (char *start, char *end)
{
- MonoArray *o;
size_t size = end - start;
if ((start && !end) || (start > end))
g_error ("Invalid range [%p %p]", start, end);
- if (size < sizeof (MonoArray)) {
- memset (start, 0, size);
- return;
+ if (sgen_client_array_fill_range (start, size)) {
+ sgen_set_nursery_scan_start (start);
+ SGEN_ASSERT (0, start + sgen_safe_object_get_size ((GCObject*)start) == end, "Array fill produced wrong size");
}
-
- o = (MonoArray*)start;
- o->obj.vtable = sgen_get_array_fill_vtable ();
- /* Mark this as not a real object */
- o->obj.synchronisation = GINT_TO_POINTER (-1);
- o->bounds = NULL;
- o->max_length = size - sizeof (MonoArray);
- sgen_set_nursery_scan_start (start);
- g_assert (start + sgen_safe_object_get_size ((MonoObject*)o) == end);
}
void
{
SGEN_LOG (4, "Found empty fragment: %p-%p, size: %zd", frag_start, frag_end, frag_size);
binary_protocol_empty (frag_start, frag_size);
- MONO_GC_NURSERY_SWEPT ((mword)frag_start, frag_end - frag_start);
/* Not worth dealing with smaller fragments: need to tune */
if (frag_size >= SGEN_MAX_NURSERY_WASTE) {
/* memsetting just the first chunk start is bound to provide better cache locality */
if (sgen_get_nursery_clear_policy () == CLEAR_AT_GC)
memset (frag_start, 0, frag_size);
+ else if (sgen_get_nursery_clear_policy () == CLEAR_AT_TLAB_CREATION_DEBUG)
+ memset (frag_start, 0xff, frag_size);
#ifdef NALLOC_DEBUG
/* XXX convert this into a flight record entry
}
mword
-sgen_build_nursery_fragments (GCMemSection *nursery_section, void **start, int num_entries, SgenGrayQueue *unpin_queue)
+sgen_build_nursery_fragments (GCMemSection *nursery_section, SgenGrayQueue *unpin_queue)
{
char *frag_start, *frag_end;
size_t frag_size;
- int i = 0;
SgenFragment *frags_ranges;
+ void **pin_start, **pin_entry, **pin_end;
#ifdef NALLOC_DEBUG
reset_alloc_records ();
/* clear scan starts */
memset (nursery_section->scan_starts, 0, nursery_section->num_scan_start * sizeof (gpointer));
- while (i < num_entries || frags_ranges) {
+ pin_start = pin_entry = sgen_pinning_get_entry (nursery_section->pin_queue_first_entry);
+ pin_end = sgen_pinning_get_entry (nursery_section->pin_queue_last_entry);
+
+ while (pin_entry < pin_end || frags_ranges) {
char *addr0, *addr1;
size_t size;
- SgenFragment *last_frag = NULL;
addr0 = addr1 = sgen_nursery_end;
- if (i < num_entries)
- addr0 = start [i];
+ if (pin_entry < pin_end)
+ addr0 = *pin_entry;
if (frags_ranges)
addr1 = frags_ranges->fragment_start;
if (addr0 < addr1) {
if (unpin_queue)
- GRAY_OBJECT_ENQUEUE (unpin_queue, addr0);
+ GRAY_OBJECT_ENQUEUE (unpin_queue, addr0, sgen_obj_get_descriptor_safe (addr0));
else
SGEN_UNPIN_OBJECT (addr0);
+ size = SGEN_ALIGN_UP (sgen_safe_object_get_size ((GCObject*)addr0));
+ CANARIFY_SIZE (size);
sgen_set_nursery_scan_start (addr0);
frag_end = addr0;
- size = SGEN_ALIGN_UP (sgen_safe_object_get_size ((MonoObject*)addr0));
- ++i;
+ ++pin_entry;
} else {
frag_end = addr1;
size = frags_ranges->fragment_next - addr1;
- last_frag = frags_ranges;
frags_ranges = frags_ranges->next_in_order;
}
frag_size = size;
#ifdef NALLOC_DEBUG
- add_alloc_record (start [i], frag_size, PINNING);
+ add_alloc_record (*pin_entry, frag_size, PINNING);
#endif
frag_start = frag_end + frag_size;
}
sgen_minor_collector.build_fragments_finish (&mutator_allocator);
if (!unmask (mutator_allocator.alloc_head)) {
- SGEN_LOG (1, "Nursery fully pinned (%d)", num_entries);
- for (i = 0; i < num_entries; ++i) {
- SGEN_LOG (3, "Bastard pinning obj %p (%s), size: %d", start [i], sgen_safe_name (start [i]), sgen_safe_object_get_size (start [i]));
+ SGEN_LOG (1, "Nursery fully pinned");
+ for (pin_entry = pin_start; pin_entry < pin_end; ++pin_entry) {
+ void *p = *pin_entry;
+ SGEN_LOG (3, "Bastard pinning obj %p (%s), size: %zd", p, sgen_client_object_safe_name (p), sgen_safe_object_get_size (p));
}
}
return fragment_total;
size = SGEN_ALIGN_UP (size);
for (frag = unmask (mutator_allocator.alloc_head); frag; frag = unmask (frag->next)) {
- if ((frag->fragment_end - frag->fragment_next) >= size)
+ if ((size_t)(frag->fragment_end - frag->fragment_next) >= size)
return TRUE;
}
return FALSE;
void*
sgen_nursery_alloc (size_t size)
{
- SGEN_ASSERT (1, size >= sizeof (MonoObject) && size <= SGEN_MAX_SMALL_OBJ_SIZE, "Invalid nursery object size");
+ SGEN_ASSERT (1, size >= sizeof (MonoObject) && size <= (SGEN_MAX_SMALL_OBJ_SIZE + CANARY_SIZE), "Invalid nursery object size");
SGEN_LOG (4, "Searching nursery for size: %zd", size);
size = SGEN_ALIGN_UP (size);
sgen_nursery_start = start;
sgen_nursery_end = end;
- sgen_space_bitmap_size = (end - start) / (SGEN_TO_SPACE_GRANULE_IN_BYTES * 8);
+ /*
+ * This will not divide evenly for tiny nurseries (<4kb), so we make sure to be on
+ * the right side of things and round up. We could just do a MIN(1,x) instead,
+ * since the nursery size must be a power of 2.
+ */
+ sgen_space_bitmap_size = (end - start + SGEN_TO_SPACE_GRANULE_IN_BYTES * 8 - 1) / (SGEN_TO_SPACE_GRANULE_IN_BYTES * 8);
sgen_space_bitmap = g_malloc0 (sgen_space_bitmap_size);
/* Setup the single first large fragment */