#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;
}
#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 (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;