Introduced a GC heap walk API.
authorPaolo Molaro <lupus@oddwiz.org>
Tue, 2 Nov 2010 17:44:29 +0000 (18:44 +0100)
committerPaolo Molaro <lupus@oddwiz.org>
Wed, 3 Nov 2010 10:42:29 +0000 (11:42 +0100)
This API is currently only implemented for the sgen GC.
It can be used to iterate over all the managed objects in the heap
and it allows to also easily track object references.

mono/metadata/boehm-gc.c
mono/metadata/mono-gc.h
mono/metadata/null-gc.c
mono/metadata/sgen-gc.c

index efe635e4cf4d0a65e2d49d85d559a85ae074d363..29ddb8a43a927b86d93de6b6868b0d67cf0a0af6 100644 (file)
@@ -320,6 +320,12 @@ mono_object_is_alive (MonoObject* o)
 #endif
 }
 
+int
+mono_gc_walk_heap (int flags, MonoGCReferences callback, void *data)
+{
+       return 1;
+}
+
 #ifdef USE_INCLUDED_LIBGC
 
 static gint64 gc_start_time;
index 750b6540db6b5f49e9b08776f3f0fbbf85e864a8..a09f9a12ed708980ac4a0ad346df9cca70599b94 100644 (file)
@@ -9,6 +9,8 @@
 
 MONO_BEGIN_DECLS
 
+typedef int (*MonoGCReferences) (MonoObject *obj, MonoClass *klass, uintptr_t size, uintptr_t num, MonoObject **refs, void *data);
+
 void   mono_gc_collect         (int generation);
 int    mono_gc_max_generation  (void);
 int    mono_gc_get_generation  (MonoObject *object);
@@ -16,6 +18,8 @@ int    mono_gc_collection_count (int generation);
 int64_t mono_gc_get_used_size   (void);
 int64_t mono_gc_get_heap_size   (void);
 int    mono_gc_invoke_finalizers (void);
+/* heap walking is only valid in the pre-stop-world event callback */
+int    mono_gc_walk_heap        (int flags, MonoGCReferences callback, void *data);
 
 MONO_END_DECLS
 
index 324d3d5c59c92934d11b1b08bb83bd86864494c8..0da8410c09da02e4f48c336754da6339d5ba64ad 100644 (file)
@@ -80,6 +80,12 @@ mono_gc_register_thread (void *baseptr)
        return TRUE;
 }
 
+int
+mono_gc_walk_heap (int flags, MonoGCReferences callback, void *data)
+{
+       return 1;
+}
+
 gboolean
 mono_object_is_alive (MonoObject* o)
 {
index 9384e7e0698565cb960677824867dfcdd40d9074..e2a7ee99560a08a4aaf1c21f4929ea9bc5739d8e 100644 (file)
@@ -6192,6 +6192,82 @@ check_object (char *start)
  * ######################################################################
  */
 
+#define REFS_SIZE 128
+typedef struct {
+       void *data;
+       MonoGCReferences callback;
+       int flags;
+       int count;
+       int called;
+       MonoObject *refs [REFS_SIZE];
+} HeapWalkInfo;
+
+#undef HANDLE_PTR
+#define HANDLE_PTR(ptr,obj)    do {    \
+               if (*(ptr)) {   \
+                       if (hwi->count == REFS_SIZE) {  \
+                               hwi->callback ((MonoObject*)start, mono_object_class (start), hwi->called? 0: size, hwi->count, hwi->refs, hwi->data);  \
+                               hwi->count = 0; \
+                               hwi->called = 1;        \
+                       }       \
+                       hwi->refs [hwi->count++] = *(ptr);      \
+               }       \
+       } while (0)
+
+static void
+collect_references (HeapWalkInfo *hwi, char *start, size_t size)
+{
+#include "sgen-scan-object.h"
+}
+
+static void
+walk_references (char *start, size_t size, void *data)
+{
+       HeapWalkInfo *hwi = data;
+       hwi->called = 0;
+       hwi->count = 0;
+       collect_references (hwi, start, size);
+       if (hwi->count || !hwi->called)
+               hwi->callback ((MonoObject*)start, mono_object_class (start), hwi->called? 0: size, hwi->count, hwi->refs, hwi->data);
+}
+
+/**
+ * mono_gc_walk_heap:
+ * @flags: flags for future use
+ * @callback: a function pointer called for each object in the heap
+ * @data: a user data pointer that is passed to callback
+ *
+ * This function can be used to iterate over all the live objects in the heap:
+ * for each object, @callback is invoked, providing info about the object's
+ * location in memory, its class, its size and the objects it references.
+ * The object references may be buffered, so the callback may be invoked
+ * multiple times for the same object: in all but the first call, the size
+ * argument will be zero.
+ * Note that this function can be only called in the #MONO_GC_EVENT_PRE_START_WORLD
+ * profiler event handler.
+ *
+ * Returns: a non-zero value if the GC doesn't support heap walking
+ */
+int
+mono_gc_walk_heap (int flags, MonoGCReferences callback, void *data)
+{
+       HeapWalkInfo hwi;
+       LOSObject *bigobj;
+
+       hwi.flags = flags;
+       hwi.callback = callback;
+       hwi.data = data;
+
+       clear_nursery_fragments (nursery_next);
+       mono_sgen_scan_area_with_callback (nursery_section->data, nursery_section->end_data, walk_references, &hwi);
+
+       major_collector.iterate_objects (TRUE, TRUE, walk_references, &hwi);
+
+       for (bigobj = los_object_list; bigobj; bigobj = bigobj->next)
+               walk_references (bigobj->data, bigobj->size, &hwi);
+       return 0;
+}
+
 void
 mono_gc_collect (int generation)
 {