static inline void
par_copy_object_no_checks (char *destination, MonoVTable *vt, void *obj, mword objsize, SgenGrayQueue *queue)
{
+ #ifdef __GNUC__
static const void *copy_labels [] = { &&LAB_0, &&LAB_1, &&LAB_2, &&LAB_3, &&LAB_4, &&LAB_5, &&LAB_6, &&LAB_7, &&LAB_8 };
+ #endif
DEBUG (9, g_assert (vt->klass->inited));
DEBUG (9, fprintf (gc_debug_file, " (to %p, %s size: %lu)\n", destination, ((MonoObject*)obj)->vtable->klass->name, (unsigned long)objsize));
binary_protocol_copy (obj, destination, vt, objsize);
-
+
+ if (G_UNLIKELY (MONO_GC_OBJ_MOVED_ENABLED ())) {
+ int dest_gen = sgen_ptr_in_nursery (destination) ? GENERATION_NURSERY : GENERATION_OLD;
+ int src_gen = sgen_ptr_in_nursery (obj) ? GENERATION_NURSERY : GENERATION_OLD;
+ MONO_GC_OBJ_MOVED ((mword)destination, (mword)obj, dest_gen, src_gen, objsize, vt->klass->name_space, vt->klass->name);
+ }
+
+ #ifdef __GNUC__
if (objsize <= sizeof (gpointer) * 8) {
mword *dest = (mword*)destination;
goto *copy_labels [objsize / sizeof (gpointer)];
/*can't trust memcpy doing word copies */
mono_gc_memmove (destination + sizeof (mword), (char*)obj + sizeof (mword), objsize - sizeof (mword));
}
+ #else
+ mono_gc_memmove (destination + sizeof (mword), (char*)obj + sizeof (mword), objsize - sizeof (mword));
+ #endif
/* adjust array->bounds */
DEBUG (9, g_assert (vt->gc_descr));
if (G_UNLIKELY (vt->rank && ((MonoArray*)obj)->bounds)) {
}
}
+ #ifdef _MSC_VER
+ static __declspec(noinline) void*
+ #else
static G_GNUC_UNUSED void* __attribute__((noinline))
+ #endif
copy_object_no_checks (void *obj, SgenGrayQueue *queue)
{
MonoVTable *vt = ((MonoObject*)obj)->vtable;
* copy_object could be made into a macro once debugged (use inline for now).
*/
+ #ifdef _MSC_VER
+ static __forceinline void
+ #else
static inline void __attribute__((always_inline))
+ #endif
serial_copy_object (void **obj_slot, SgenGrayQueue *queue)
{
char *forwarded;
#include "metadata/sgen-archdep.h"
#include "metadata/sgen-bridge.h"
#include "metadata/sgen-memory-governor.h"
+#include "metadata/sgen-hash-table.h"
#include "metadata/mono-gc.h"
#include "metadata/method-builder.h"
#include "metadata/profiler-private.h"
#include "utils/mono-proclib.h"
#include "utils/mono-memory-model.h"
#include "utils/mono-logger-internal.h"
+#include "utils/dtrace.h"
#include <mono/utils/mono-logger-internal.h>
#include <mono/utils/memcheck.h>
if (addr >= search_start && (char*)addr < (char*)last_obj + last_obj_size) {
DEBUG (4, fprintf (gc_debug_file, "Pinned object %p, vtable %p (%s), count %d\n", search_start, *(void**)search_start, safe_name (search_start), count));
binary_protocol_pin (search_start, (gpointer)LOAD_VTABLE (search_start), safe_object_get_size (search_start));
+ if (G_UNLIKELY (MONO_GC_OBJ_PINNED_ENABLED ())) {
+ int gen = sgen_ptr_in_nursery (search_start) ? GENERATION_NURSERY : GENERATION_OLD;
+ MonoVTable *vt = (MonoVTable*)LOAD_VTABLE (search_start);
+ MONO_GC_OBJ_PINNED ((mword)search_start, sgen_safe_object_get_size (search_start), vt->klass->name_space, vt->klass->name, gen);
+ }
pin_object (search_start);
GRAY_OBJECT_ENQUEUE (queue, search_start);
if (G_UNLIKELY (do_pin_stats))
}
GRAY_OBJECT_ENQUEUE (queue, object);
binary_protocol_pin (object, (gpointer)LOAD_VTABLE (object), safe_object_get_size (object));
+ if (G_UNLIKELY (MONO_GC_OBJ_PINNED_ENABLED ())) {
+ int gen = sgen_ptr_in_nursery (object) ? GENERATION_NURSERY : GENERATION_OLD;
+ MonoVTable *vt = (MonoVTable*)LOAD_VTABLE (object);
+ MONO_GC_OBJ_PINNED ((mword)object, sgen_safe_object_get_size (object), vt->klass->name_space, vt->klass->name, gen);
+ }
}
void
section->size = alloc_size;
section->end_data = data + sgen_nursery_size;
scan_starts = (alloc_size + SCAN_START_SIZE - 1) / SCAN_START_SIZE;
- section->scan_starts = sgen_alloc_internal_dynamic (sizeof (char*) * scan_starts, INTERNAL_MEM_SCAN_STARTS);
+ section->scan_starts = sgen_alloc_internal_dynamic (sizeof (char*) * scan_starts, INTERNAL_MEM_SCAN_STARTS, TRUE);
section->num_scan_start = scan_starts;
section->block.role = MEMORY_ROLE_GEN0;
section->block.next = NULL;
}
static void
-bridge_process (void)
+bridge_process (int generation)
{
- sgen_bridge_processing_finish ();
+ sgen_bridge_processing_finish (generation);
}
SgenObjectOperations *
if (disable_minor_collections)
return TRUE;
+ MONO_GC_BEGIN (GENERATION_NURSERY);
+
verify_nursery ();
mono_perfcounters->gc_collections0++;
sgen_workers_init_distribute_gray_queue ();
stat_minor_gcs++;
- mono_stats.minor_gc_count ++;
+ gc_stats.minor_gc_count ++;
if (remset.prepare_for_minor_collection)
remset.prepare_for_minor_collection ();
major_collector.finish_nursery_collection ();
TV_GETTIME (all_btv);
- mono_stats.minor_gc_time_usecs += TV_ELAPSED (all_atv, all_btv);
+ gc_stats.minor_gc_time_usecs += TV_ELAPSED (all_atv, all_btv);
if (heap_dump_file)
dump_heap ("minor", stat_minor_gcs - 1, NULL);
current_collection_generation = -1;
objects_pinned = 0;
+ MONO_GC_END (GENERATION_NURSERY);
+
return needs_major;
}
ScanThreadDataJobData stdjd;
ScanFinalizerEntriesJobData sfejd_fin_ready, sfejd_critical_fin;
+ MONO_GC_BEGIN (GENERATION_OLD);
+
current_collection_generation = GENERATION_OLD;
mono_perfcounters->gc_collections1++;
degraded_mode = 0;
DEBUG (1, fprintf (gc_debug_file, "Start major collection %d\n", stat_major_gcs));
stat_major_gcs++;
- mono_stats.major_gc_count ++;
+ gc_stats.major_gc_count ++;
/* world must be stopped already */
TV_GETTIME (all_atv);
report.count = 0;
if (sgen_find_optimized_pin_queue_area (bigobj->data, (char*)bigobj->data + bigobj->size, &dummy)) {
binary_protocol_pin (bigobj->data, (gpointer)LOAD_VTABLE (bigobj->data), safe_object_get_size (bigobj->data));
+ if (G_UNLIKELY (MONO_GC_OBJ_PINNED_ENABLED ())) {
+ MonoVTable *vt = (MonoVTable*)LOAD_VTABLE (bigobj->data);
+ MONO_GC_OBJ_PINNED ((mword)bigobj->data, sgen_safe_object_get_size ((MonoObject*)bigobj->data), vt->klass->name_space, vt->klass->name, GENERATION_OLD);
+ }
pin_object (bigobj->data);
/* FIXME: only enqueue if object has references */
GRAY_OBJECT_ENQUEUE (WORKERS_DISTRIBUTE_GRAY_QUEUE, bigobj->data);
time_major_fragment_creation += TV_ELAPSED (btv, atv);
TV_GETTIME (all_btv);
- mono_stats.major_gc_time_usecs += TV_ELAPSED (all_atv, all_btv);
+ gc_stats.major_gc_time_usecs += TV_ELAPSED (all_atv, all_btv);
if (heap_dump_file)
dump_heap ("major", stat_major_gcs - 1, reason);
//consistency_check ();
+ MONO_GC_END (GENERATION_OLD);
+
return bytes_pinned_from_failed_allocation > 0;
}
{
int stack_guard = 0;
#ifndef USE_MONO_CTX
- void *ptr = cur_thread_regs;
+ void *reg_ptr = cur_thread_regs;
#endif
SgenThreadInfo *info = mono_thread_info_current ();
#ifdef USE_MONO_CTX
MONO_CONTEXT_GET_CURRENT (cur_thread_ctx);
info->monoctx = &cur_thread_ctx;
+ if (gc_callbacks.thread_suspend_func)
+ gc_callbacks.thread_suspend_func (info->runtime_data, NULL, info->monoctx);
#else
- ARCH_STORE_REGS (ptr);
- info->stopped_regs = ptr;
+ ARCH_STORE_REGS (reg_ptr);
+ info->stopped_regs = reg_ptr;
-#endif
if (gc_callbacks.thread_suspend_func)
- gc_callbacks.thread_suspend_func (info->runtime_data, NULL);
+ gc_callbacks.thread_suspend_func (info->runtime_data, NULL, NULL);
+#endif
}
void
DEBUG (2, fprintf (gc_debug_file, "restarted %d thread(s) (pause time: %d usec, max: %d)\n", count, (int)usec, (int)max_pause_usec));
mono_profiler_gc_event (MONO_GC_EVENT_POST_START_WORLD, generation);
- bridge_process ();
+ bridge_process (generation);
TV_GETTIME (end_bridge);
bridge_usec = TV_ELAPSED (end_sw, end_bridge);
if (!sgen_park_current_thread_if_doing_handshake (p))
g_usleep (50);
}
+ MONO_GC_LOCKED ();
#endif
binary_protocol_thread_unregister ((gpointer)mono_thread_info_get_tid (p));
MonoObject*
mono_gc_weak_link_get (void **link_addr)
{
- if (!*link_addr)
+ /*
+ * We must only load *link_addr once because it might change
+ * under our feet, and REVEAL_POINTER (NULL) results in an
+ * invalid reference.
+ */
+ void *ptr = *link_addr;
+ if (!ptr)
return NULL;
- return (MonoObject*) REVEAL_POINTER (*link_addr);
+
+ /*
+ * During the second bridge processing step the world is
+ * running again. That step processes all weak links once
+ * more to null those that refer to dead objects. Before that
+ * is completed, those links must not be followed, so we
+ * conservatively wait for bridge processing when any weak
+ * link is dereferenced.
+ */
+ if (G_UNLIKELY (bridge_processing_in_progress))
+ mono_gc_wait_for_bridge_processing ();
+
+ return (MonoObject*) REVEAL_POINTER (ptr);
}
gboolean
fprintf (stderr, "The major collector does not support the cardtable write barrier.\n");
exit (1);
}
+ } else {
+ fprintf (stderr, "wbarrier must either be `remset' or `cardtable'.");
+ exit (1);
}
continue;
}
return (method == write_barrier_method || sgen_is_managed_allocator (method));
}
+static gboolean
+sgen_has_critical_method (void)
+{
+ return write_barrier_method || sgen_has_managed_allocator ();
+}
+
static gboolean
is_ip_in_managed_allocator (MonoDomain *domain, gpointer ip)
{
if (!ip || !domain)
return FALSE;
+ if (!sgen_has_critical_method ())
+ return FALSE;
ji = mono_jit_info_table_find (domain, ip);
if (!ji)
return FALSE;
};
#ifdef FIXED_HEAP
-static int ms_heap_num_blocks = MS_DEFAULT_HEAP_NUM_BLOCKS;
+static mword ms_heap_num_blocks = MS_DEFAULT_HEAP_NUM_BLOCKS;
static char *ms_heap_start;
static char *ms_heap_end;
char *nursery_start;
mword major_heap_size = ms_heap_num_blocks * MS_BLOCK_SIZE;
mword alloc_size = nursery_size + major_heap_size;
- int i;
+ mword i;
g_assert (ms_heap_num_blocks > 0);
g_assert (nursery_size % MS_BLOCK_SIZE == 0);
if (nursery_align)
g_assert (nursery_align % MS_BLOCK_SIZE == 0);
- nursery_start = sgen_alloc_os_memory_aligned (alloc_size, nursery_align ? nursery_align : MS_BLOCK_SIZE, TRUE);
+ nursery_start = sgen_alloc_os_memory_aligned (alloc_size, nursery_align ? nursery_align : MS_BLOCK_SIZE, SGEN_ALLOC_HEAP | SGEN_ALLOC_ACTIVATE, "heap");
ms_heap_start = nursery_start + nursery_size;
ms_heap_end = ms_heap_start + major_heap_size;
- block_infos = sgen_alloc_internal_dynamic (sizeof (MSBlockInfo) * ms_heap_num_blocks, INTERNAL_MEM_MS_BLOCK_INFO);
+ block_infos = sgen_alloc_internal_dynamic (sizeof (MSBlockInfo) * ms_heap_num_blocks, INTERNAL_MEM_MS_BLOCK_INFO, TRUE);
for (i = 0; i < ms_heap_num_blocks; ++i) {
block_infos [i].block = ms_heap_start + i * MS_BLOCK_SIZE;
{
char *start;
if (nursery_align)
- start = sgen_alloc_os_memory_aligned (nursery_size, nursery_align, TRUE);
+ start = sgen_alloc_os_memory_aligned (nursery_size, nursery_align, SGEN_ALLOC_HEAP | SGEN_ALLOC_ACTIVATE, "nursery");
else
- start = sgen_alloc_os_memory (nursery_size, TRUE);
+ start = sgen_alloc_os_memory (nursery_size, SGEN_ALLOC_HEAP | SGEN_ALLOC_ACTIVATE, "nursery");
return start;
}
retry:
if (!empty_blocks) {
- p = sgen_alloc_os_memory_aligned (MS_BLOCK_SIZE * MS_BLOCK_ALLOC_NUM, MS_BLOCK_SIZE, TRUE);
+ p = sgen_alloc_os_memory_aligned (MS_BLOCK_SIZE * MS_BLOCK_ALLOC_NUM, MS_BLOCK_SIZE, SGEN_ALLOC_HEAP | SGEN_ALLOC_ACTIVATE, "major heap section");
for (i = 0; i < MS_BLOCK_ALLOC_NUM; ++i) {
block = p;
if (SGEN_OBJECT_IS_PINNED (obj))
return;
binary_protocol_pin (obj, (gpointer)SGEN_LOAD_VTABLE (obj), sgen_safe_object_get_size ((MonoObject*)obj));
+ if (G_UNLIKELY (MONO_GC_OBJ_PINNED_ENABLED ())) {
+ MonoVTable *vt = (MonoVTable*)SGEN_LOAD_VTABLE (obj);
+ MONO_GC_OBJ_PINNED ((mword)obj, sgen_safe_object_get_size (obj), vt->klass->name_space, vt->klass->name, GENERATION_OLD);
+ }
SGEN_PIN_OBJECT (obj);
/* FIXME: only enqueue if object has references */
GRAY_OBJECT_ENQUEUE (queue, obj);
} else {
/* an unmarked object */
if (MS_OBJ_ALLOCED (obj, block)) {
+ /*
+ * FIXME: Merge consecutive
+ * slots for lower reporting
+ * overhead. Maybe memset
+ * will also benefit?
+ */
binary_protocol_empty (obj, block->obj_size);
+ MONO_GC_MAJOR_SWEPT ((mword)obj, block->obj_size);
memset (obj, 0, block->obj_size);
}
*(void**)obj = block->free_list;
++count_pinned_nonref;
}
- static void __attribute__ ((unused))
+ static G_GNUC_UNUSED void
count_ref_nonref_objs (void)
{
int total;
while (num_empty_blocks > section_reserve) {
void *next = *(void**)empty_blocks;
- sgen_free_os_memory (empty_blocks, MS_BLOCK_SIZE);
+ sgen_free_os_memory (empty_blocks, MS_BLOCK_SIZE, SGEN_ALLOC_HEAP);
empty_blocks = next;
/*
* Needs not be atomic because this is running
{
int i;
for (i = 0; i < MS_BLOCK_TYPE_MAX; ++i)
- lists [i] = sgen_alloc_internal_dynamic (sizeof (MSBlockInfo*) * num_block_obj_sizes, INTERNAL_MEM_MS_TABLES);
+ lists [i] = sgen_alloc_internal_dynamic (sizeof (MSBlockInfo*) * num_block_obj_sizes, INTERNAL_MEM_MS_TABLES, TRUE);
}
#ifdef SGEN_PARALLEL_MARK
#endif
num_block_obj_sizes = ms_calculate_block_obj_sizes (MS_BLOCK_OBJ_SIZE_FACTOR, NULL);
- block_obj_sizes = sgen_alloc_internal_dynamic (sizeof (int) * num_block_obj_sizes, INTERNAL_MEM_MS_TABLES);
+ block_obj_sizes = sgen_alloc_internal_dynamic (sizeof (int) * num_block_obj_sizes, INTERNAL_MEM_MS_TABLES, TRUE);
ms_calculate_block_obj_sizes (MS_BLOCK_OBJ_SIZE_FACTOR, block_obj_sizes);
- evacuate_block_obj_sizes = sgen_alloc_internal_dynamic (sizeof (gboolean) * num_block_obj_sizes, INTERNAL_MEM_MS_TABLES);
+ evacuate_block_obj_sizes = sgen_alloc_internal_dynamic (sizeof (gboolean) * num_block_obj_sizes, INTERNAL_MEM_MS_TABLES, TRUE);
for (i = 0; i < num_block_obj_sizes; ++i)
evacuate_block_obj_sizes [i] = FALSE;