6 * Paolo Molaro (lupus@ximian.com)
7 * Rodrigo Kumpera (kumpera@gmail.com)
9 * Copyright 2005-2011 Novell, Inc (http://www.novell.com)
10 * Copyright 2011 Xamarin Inc (http://www.xamarin.com)
11 * Copyright 2011 Xamarin, Inc.
12 * Copyright (C) 2012 Xamarin Inc
14 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
22 #include "mono/sgen/sgen-gc.h"
23 #include "mono/sgen/sgen-cardtable.h"
24 #include "mono/sgen/sgen-protocol.h"
25 #include "mono/sgen/sgen-memory-governor.h"
26 #include "mono/sgen/sgen-pinning.h"
27 #include "mono/sgen/sgen-client.h"
29 #define LOAD_VTABLE SGEN_LOAD_VTABLE
31 #define object_is_forwarded SGEN_OBJECT_IS_FORWARDED
32 #define object_is_pinned SGEN_OBJECT_IS_PINNED
33 #define safe_object_get_size sgen_safe_object_get_size
35 void describe_ptr (char *ptr
);
36 void check_object (GCObject
*obj
);
39 * ######################################################################
40 * ######## Collector debugging
41 * ######################################################################
44 static const char*descriptor_types
[] = {
52 "complex pointer-free"
55 static char* describe_nursery_ptr (char *ptr
, gboolean need_setup
);
58 describe_pointer (char *ptr
, gboolean need_setup
)
68 if (sgen_ptr_in_nursery (ptr
)) {
69 start
= describe_nursery_ptr (ptr
, need_setup
);
73 vtable
= LOAD_VTABLE ((GCObject
*)ptr
);
75 if (sgen_ptr_is_in_los (ptr
, &start
)) {
77 printf ("Pointer is the start of object %p in LOS space.\n", start
);
79 printf ("Pointer is at offset 0x%x of object %p in LOS space.\n", (int)(ptr
- start
), start
);
81 mono_sgen_los_describe_pointer (ptr
);
82 vtable
= LOAD_VTABLE ((GCObject
*)ptr
);
83 } else if (major_collector
.ptr_is_in_non_pinned_space (ptr
, &start
)) {
85 printf ("Pointer is the start of object %p in oldspace.\n", start
);
87 printf ("Pointer is at offset 0x%x of object %p in oldspace.\n", (int)(ptr
- start
), start
);
89 printf ("Pointer inside oldspace.\n");
92 vtable
= (GCVTable
)major_collector
.describe_pointer (ptr
);
93 } else if (major_collector
.ptr_is_from_pinned_alloc (ptr
)) {
94 // FIXME: Handle pointers to the inside of objects
95 printf ("Pointer is inside a pinned chunk.\n");
96 vtable
= LOAD_VTABLE ((GCObject
*)ptr
);
98 printf ("Pointer unknown.\n");
103 if (object_is_pinned (ptr
))
104 printf ("Object is pinned.\n");
106 if ((forwarded
= (char *)object_is_forwarded (ptr
))) {
107 printf ("Object is forwarded to %p:\n", forwarded
);
112 printf ("VTable: %p\n", vtable
);
113 if (vtable
== NULL
) {
114 printf ("VTable is invalid (empty).\n");
117 if (sgen_ptr_in_nursery (vtable
)) {
118 printf ("VTable is invalid (points inside nursery).\n");
121 printf ("Class: %s.%s\n", sgen_client_vtable_get_namespace (vtable
), sgen_client_vtable_get_name (vtable
));
123 desc
= sgen_vtable_get_descriptor (vtable
);
124 printf ("Descriptor: %lx\n", (long)desc
);
126 type
= desc
& DESC_TYPE_MASK
;
127 printf ("Descriptor type: %d (%s)\n", type
, descriptor_types
[type
]);
129 size
= sgen_safe_object_get_size ((GCObject
*)ptr
);
130 printf ("Size: %d\n", (int)size
);
134 sgen_client_describe_invalid_pointer ((GCObject
*) ptr
);
138 describe_ptr (char *ptr
)
140 describe_pointer (ptr
, TRUE
);
143 static gboolean missing_remsets
;
146 * We let a missing remset slide if the target object is pinned,
147 * because the store might have happened but the remset not yet added,
148 * but in that case the target must be pinned. We might theoretically
149 * miss some missing remsets this way, but it's very unlikely.
152 #define HANDLE_PTR(ptr,obj) do { \
153 if (*(ptr) && sgen_ptr_in_nursery ((char*)*(ptr))) { \
154 if (!sgen_get_remset ()->find_address ((char*)(ptr)) && !sgen_cement_lookup (*(ptr))) { \
155 GCVTable __vt = SGEN_LOAD_VTABLE (obj); \
156 gboolean is_pinned = object_is_pinned (*(ptr)); \
157 SGEN_LOG (0, "Oldspace->newspace reference %p at offset %zd in object %p (%s.%s) not found in remsets%s.", *(ptr), (char*)(ptr) - (char*)(obj), (obj), sgen_client_vtable_get_namespace (__vt), sgen_client_vtable_get_name (__vt), is_pinned ? ", but object is pinned" : ""); \
158 binary_protocol_missing_remset ((obj), __vt, (int) ((char*)(ptr) - (char*)(obj)), *(ptr), (gpointer)LOAD_VTABLE(*(ptr)), is_pinned); \
160 missing_remsets = TRUE; \
166 * Check that each object reference which points into the nursery can
167 * be found in the remembered sets.
170 check_consistency_callback (GCObject
*obj
, size_t size
, void *dummy
)
172 char *start
= (char*)obj
;
173 GCVTable vt
= LOAD_VTABLE (obj
);
174 SgenDescriptor desc
= sgen_vtable_get_descriptor (vt
);
175 SGEN_LOG (8, "Scanning object %p, vtable: %p (%s)", start
, vt
, sgen_client_vtable_get_name (vt
));
177 #include "sgen-scan-object.h"
181 * Perform consistency check of the heap.
183 * Assumes the world is stopped.
186 sgen_check_remset_consistency (void)
188 // Need to add more checks
190 missing_remsets
= FALSE
;
192 SGEN_LOG (1, "Begin heap consistency check...");
194 // Check that oldspace->newspace pointers are registered with the collector
195 major_collector
.iterate_objects (ITERATE_OBJECTS_SWEEP_ALL
, (IterateObjectCallbackFunc
)check_consistency_callback
, NULL
);
197 sgen_los_iterate_objects ((IterateObjectCallbackFunc
)check_consistency_callback
, NULL
);
199 SGEN_LOG (1, "Heap consistency check done.");
202 binary_protocol_flush_buffers (TRUE
);
203 if (!binary_protocol_is_enabled ())
204 g_assert (!missing_remsets
);
208 is_major_or_los_object_marked (GCObject
*obj
)
210 if (sgen_safe_object_get_size ((GCObject
*)obj
) > SGEN_MAX_SMALL_OBJ_SIZE
) {
211 return sgen_los_object_is_pinned (obj
);
213 return sgen_get_major_collector ()->is_object_live (obj
);
218 #define HANDLE_PTR(ptr,obj) do { \
219 if (*(ptr) && !sgen_ptr_in_nursery ((char*)*(ptr)) && !is_major_or_los_object_marked ((GCObject*)*(ptr))) { \
220 if (!cards || !sgen_get_remset ()->find_address_with_cards (start, cards, (char*)(ptr))) { \
221 GCVTable __vt = SGEN_LOAD_VTABLE (obj); \
222 SGEN_LOG (0, "major->major reference %p at offset %zd in object %p (%s.%s) not found in remsets.", *(ptr), (char*)(ptr) - (char*)(obj), (obj), sgen_client_vtable_get_namespace (__vt), sgen_client_vtable_get_name (__vt)); \
223 binary_protocol_missing_remset ((obj), __vt, (int) ((char*)(ptr) - (char*)(obj)), *(ptr), (gpointer)LOAD_VTABLE(*(ptr)), object_is_pinned (*(ptr))); \
224 missing_remsets = TRUE; \
230 check_mod_union_callback (GCObject
*obj
, size_t size
, void *dummy
)
232 char *start
= (char*)obj
;
233 gboolean in_los
= (gboolean
) (size_t) dummy
;
234 GCVTable vt
= LOAD_VTABLE (obj
);
235 SgenDescriptor desc
= sgen_vtable_get_descriptor (vt
);
237 SGEN_LOG (8, "Scanning object %p, vtable: %p (%s)", obj
, vt
, sgen_client_vtable_get_name (vt
));
239 if (!is_major_or_los_object_marked (obj
))
243 cards
= sgen_los_header_for_object (obj
)->cardtable_mod_union
;
245 cards
= sgen_get_major_collector ()->get_cardtable_mod_union_for_reference (start
);
247 #include "sgen-scan-object.h"
251 sgen_check_mod_union_consistency (void)
253 missing_remsets
= FALSE
;
255 major_collector
.iterate_objects (ITERATE_OBJECTS_SWEEP_ALL
, (IterateObjectCallbackFunc
)check_mod_union_callback
, (void*)FALSE
);
257 sgen_los_iterate_objects ((IterateObjectCallbackFunc
)check_mod_union_callback
, (void*)TRUE
);
259 if (!binary_protocol_is_enabled ())
260 g_assert (!missing_remsets
);
264 #define HANDLE_PTR(ptr,obj) do { \
265 if (*(ptr) && !LOAD_VTABLE (*(ptr))) \
266 g_error ("Could not load vtable for obj %p slot %zd (size %zd)", obj, (char*)ptr - (char*)obj, (size_t)safe_object_get_size ((GCObject*)obj)); \
270 check_major_refs_callback (GCObject
*obj
, size_t size
, void *dummy
)
272 char *start
= (char*)obj
;
273 SgenDescriptor desc
= sgen_obj_get_descriptor (obj
);
275 #include "sgen-scan-object.h"
279 sgen_check_major_refs (void)
281 major_collector
.iterate_objects (ITERATE_OBJECTS_SWEEP_ALL
, (IterateObjectCallbackFunc
)check_major_refs_callback
, NULL
);
282 sgen_los_iterate_objects ((IterateObjectCallbackFunc
)check_major_refs_callback
, NULL
);
285 /* Check that the reference is valid */
287 #define HANDLE_PTR(ptr,obj) do { \
289 g_assert (sgen_client_vtable_get_namespace (SGEN_LOAD_VTABLE_UNCHECKED (*(ptr)))); \
296 * Perform consistency check on an object. Currently we only check that the
297 * reference fields are valid.
300 check_object (GCObject
*obj
)
302 char *start
= (char*)obj
;
308 desc
= sgen_obj_get_descriptor (obj
);
310 #include "sgen-scan-object.h"
314 static GCObject
**valid_nursery_objects
;
315 static int valid_nursery_object_count
;
316 static gboolean broken_heap
;
319 setup_mono_sgen_scan_area_with_callback (GCObject
*object
, size_t size
, void *data
)
321 valid_nursery_objects
[valid_nursery_object_count
++] = object
;
325 setup_valid_nursery_objects (void)
327 if (!valid_nursery_objects
)
328 valid_nursery_objects
= (GCObject
**)sgen_alloc_os_memory (sgen_nursery_size
, (SgenAllocFlags
)(SGEN_ALLOC_INTERNAL
| SGEN_ALLOC_ACTIVATE
), "debugging data", MONO_MEM_ACCOUNT_SGEN_DEBUGGING
);
329 valid_nursery_object_count
= 0;
330 sgen_scan_area_with_callback (nursery_section
->data
, nursery_section
->end_data
, setup_mono_sgen_scan_area_with_callback
, NULL
, FALSE
, FALSE
);
334 find_object_in_nursery_dump (char *object
)
336 int first
= 0, last
= valid_nursery_object_count
;
337 while (first
< last
) {
338 int middle
= first
+ ((last
- first
) >> 1);
339 if (object
== (char*)valid_nursery_objects
[middle
])
342 if (object
< (char*)valid_nursery_objects
[middle
])
347 g_assert (first
== last
);
352 iterate_valid_nursery_objects (IterateObjectCallbackFunc callback
, void *data
)
355 for (i
= 0; i
< valid_nursery_object_count
; ++i
) {
356 GCObject
*obj
= valid_nursery_objects
[i
];
357 callback (obj
, safe_object_get_size (obj
), data
);
362 describe_nursery_ptr (char *ptr
, gboolean need_setup
)
367 setup_valid_nursery_objects ();
369 for (i
= 0; i
< valid_nursery_object_count
- 1; ++i
) {
370 if ((char*)valid_nursery_objects
[i
+ 1] > ptr
)
374 if (i
>= valid_nursery_object_count
|| (char*)valid_nursery_objects
[i
] + safe_object_get_size (valid_nursery_objects
[i
]) < ptr
) {
375 SGEN_LOG (0, "nursery-ptr (unalloc'd-memory)");
378 GCObject
*obj
= valid_nursery_objects
[i
];
379 if ((char*)obj
== ptr
)
380 SGEN_LOG (0, "nursery-ptr %p", obj
);
382 SGEN_LOG (0, "nursery-ptr %p (interior-ptr offset %zd)", obj
, ptr
- (char*)obj
);
388 is_valid_object_pointer (char *object
)
390 if (sgen_ptr_in_nursery (object
))
391 return find_object_in_nursery_dump (object
);
393 if (sgen_los_is_valid_object (object
))
396 if (major_collector
.is_valid_object (object
))
402 bad_pointer_spew (char *obj
, char **slot
)
405 GCVTable vtable
= LOAD_VTABLE ((GCObject
*)obj
);
407 SGEN_LOG (0, "Invalid object pointer %p at offset %zd in object %p (%s.%s):", ptr
,
409 obj
, sgen_client_vtable_get_namespace (vtable
), sgen_client_vtable_get_name (vtable
));
410 describe_pointer (ptr
, FALSE
);
415 missing_remset_spew (char *obj
, char **slot
)
418 GCVTable vtable
= LOAD_VTABLE ((GCObject
*)obj
);
420 SGEN_LOG (0, "Oldspace->newspace reference %p at offset %zd in object %p (%s.%s) not found in remsets.",
421 ptr
, (char*)slot
- obj
, obj
,
422 sgen_client_vtable_get_namespace (vtable
), sgen_client_vtable_get_name (vtable
));
428 FIXME Flag missing remsets due to pinning as non fatal
431 #define HANDLE_PTR(ptr,obj) do { \
432 if (*(char**)ptr) { \
433 if (!is_valid_object_pointer (*(char**)ptr)) { \
434 bad_pointer_spew ((char*)obj, (char**)ptr); \
435 } else if (!sgen_ptr_in_nursery (obj) && sgen_ptr_in_nursery ((char*)*ptr)) { \
436 if (!allow_missing_pinned && !SGEN_OBJECT_IS_PINNED (*(ptr)) && !sgen_get_remset ()->find_address ((char*)(ptr)) && !sgen_cement_lookup (*(ptr))) \
437 missing_remset_spew ((char*)obj, (char**)ptr); \
443 verify_object_pointers_callback (GCObject
*obj
, size_t size
, void *data
)
445 char *start
= (char*)obj
;
446 gboolean allow_missing_pinned
= (gboolean
) (size_t) data
;
447 SgenDescriptor desc
= sgen_obj_get_descriptor_safe (obj
);
449 #include "sgen-scan-object.h"
454 -This heap checker is racy regarding inlined write barriers and other JIT tricks that
455 depend on OP_DUMMY_USE.
458 sgen_check_whole_heap (gboolean allow_missing_pinned
)
460 setup_valid_nursery_objects ();
463 sgen_scan_area_with_callback (nursery_section
->data
, nursery_section
->end_data
, verify_object_pointers_callback
, (void*) (size_t) allow_missing_pinned
, FALSE
, TRUE
);
464 major_collector
.iterate_objects (ITERATE_OBJECTS_SWEEP_ALL
, verify_object_pointers_callback
, (void*) (size_t) allow_missing_pinned
);
465 sgen_los_iterate_objects (verify_object_pointers_callback
, (void*) (size_t) allow_missing_pinned
);
467 g_assert (!broken_heap
);
471 ptr_in_heap (char *object
)
473 if (sgen_ptr_in_nursery (object
))
476 if (sgen_los_is_valid_object (object
))
479 if (major_collector
.is_valid_object (object
))
486 * Do consistency checks on the object reference OBJ. Assert on failure.
489 sgen_check_objref (char *obj
)
491 g_assert (ptr_in_heap (obj
));
495 find_pinning_ref_from_thread (char *obj
, size_t size
)
497 #ifndef SGEN_WITHOUT_MONO
498 char *endobj
= obj
+ size
;
500 FOREACH_THREAD (info
) {
501 mword
*ctxstart
, *ctxcurrent
, *ctxend
;
502 char **start
= (char**)info
->client_info
.stack_start
;
503 if (info
->client_info
.skip
|| info
->client_info
.gc_disabled
)
505 while (start
< (char**)info
->client_info
.stack_end
) {
506 if (*start
>= obj
&& *start
< endobj
)
507 SGEN_LOG (0, "Object %p referenced in thread %p (id %p) at %p, stack: %p-%p", obj
, info
, (gpointer
)mono_thread_info_get_tid (info
), start
, info
->client_info
.stack_start
, info
->client_info
.stack_end
);
511 for (ctxstart
= ctxcurrent
= (mword
*) &info
->client_info
.ctx
, ctxend
= (mword
*) (&info
->client_info
.ctx
+ 1); ctxcurrent
< ctxend
; ctxcurrent
++) {
512 mword w
= *ctxcurrent
;
514 if (w
>= (mword
)obj
&& w
< (mword
)obj
+ size
)
515 SGEN_LOG (0, "Object %p referenced in saved reg %d of thread %p (id %p)", obj
, (int) (ctxcurrent
- ctxstart
), info
, (gpointer
)mono_thread_info_get_tid (info
));
522 * Debugging function: find in the conservative roots where @obj is being pinned.
524 static G_GNUC_UNUSED
void
525 find_pinning_reference (char *obj
, size_t size
)
529 char *endobj
= obj
+ size
;
531 SGEN_HASH_TABLE_FOREACH (&roots_hash
[ROOT_TYPE_NORMAL
], char **, start
, RootRecord
*, root
) {
532 /* if desc is non-null it has precise info */
533 if (!root
->root_desc
) {
534 while (start
< (char**)root
->end_root
) {
535 if (*start
>= obj
&& *start
< endobj
) {
536 SGEN_LOG (0, "Object %p referenced in pinned roots %p-%p\n", obj
, start
, root
->end_root
);
541 } SGEN_HASH_TABLE_FOREACH_END
;
543 find_pinning_ref_from_thread (obj
, size
);
547 #define HANDLE_PTR(ptr,obj) do { \
548 char* __target = *(char**)ptr; \
550 if (sgen_ptr_in_nursery (__target)) { \
551 g_assert (!SGEN_OBJECT_IS_FORWARDED (__target)); \
553 mword __size = sgen_safe_object_get_size ((GCObject*)__target); \
554 if (__size <= SGEN_MAX_SMALL_OBJ_SIZE) \
555 g_assert (major_collector.is_object_live ((GCObject*)__target)); \
557 g_assert (sgen_los_object_is_pinned ((GCObject*)__target)); \
563 check_marked_callback (GCObject
*obj
, size_t size
, void *dummy
)
565 char *start
= (char*)obj
;
566 gboolean flag
= (gboolean
) (size_t) dummy
;
569 if (sgen_ptr_in_nursery (start
)) {
571 SGEN_ASSERT (0, SGEN_OBJECT_IS_PINNED (obj
), "All objects remaining in the nursery must be pinned");
573 if (!sgen_los_object_is_pinned (obj
))
576 if (!major_collector
.is_object_live (obj
))
580 desc
= sgen_obj_get_descriptor_safe (obj
);
582 #include "sgen-scan-object.h"
586 sgen_check_heap_marked (gboolean nursery_must_be_pinned
)
588 setup_valid_nursery_objects ();
590 iterate_valid_nursery_objects (check_marked_callback
, (void*)(size_t)nursery_must_be_pinned
);
591 major_collector
.iterate_objects (ITERATE_OBJECTS_SWEEP_ALL
, check_marked_callback
, (void*)FALSE
);
592 sgen_los_iterate_objects (check_marked_callback
, (void*)TRUE
);
596 check_nursery_objects_pinned_callback (char *obj
, size_t size
, void *data
/* ScanCopyContext *ctx */)
598 gboolean pinned
= (gboolean
) (size_t) data
;
600 g_assert (!SGEN_OBJECT_IS_FORWARDED (obj
));
602 g_assert (SGEN_OBJECT_IS_PINNED (obj
));
604 g_assert (!SGEN_OBJECT_IS_PINNED (obj
));
608 sgen_check_nursery_objects_pinned (gboolean pinned
)
610 sgen_clear_nursery_fragments ();
611 sgen_scan_area_with_callback (nursery_section
->data
, nursery_section
->end_data
,
612 (IterateObjectCallbackFunc
)check_nursery_objects_pinned_callback
, (void*) (size_t) pinned
/* (void*)&ctx */, FALSE
, TRUE
);
616 verify_scan_starts (char *start
, char *end
)
620 for (i
= 0; i
< nursery_section
->num_scan_start
; ++i
) {
621 char *addr
= nursery_section
->scan_starts
[i
];
622 if (addr
> start
&& addr
< end
)
623 SGEN_LOG (0, "NFC-BAD SCAN START [%zu] %p for obj [%p %p]", i
, addr
, start
, end
);
628 sgen_debug_verify_nursery (gboolean do_dump_nursery_content
)
630 char *start
, *end
, *cur
, *hole_start
;
632 if (nursery_canaries_enabled ())
633 SGEN_LOG (0, "Checking nursery canaries...");
635 /*This cleans up unused fragments */
636 sgen_nursery_allocator_prepare_for_pinning ();
638 hole_start
= start
= cur
= sgen_get_nursery_start ();
639 end
= sgen_get_nursery_end ();
643 gboolean is_array_fill
;
646 cur
+= sizeof (void*);
650 if (object_is_forwarded (cur
))
651 SGEN_LOG (0, "FORWARDED OBJ %p", cur
);
652 else if (object_is_pinned (cur
))
653 SGEN_LOG (0, "PINNED OBJ %p", cur
);
655 ss
= safe_object_get_size ((GCObject
*)cur
);
656 size
= SGEN_ALIGN_UP (ss
);
657 verify_scan_starts (cur
, cur
+ size
);
658 is_array_fill
= sgen_client_object_is_array_fill ((GCObject
*)cur
);
659 if (do_dump_nursery_content
) {
660 GCVTable vtable
= SGEN_LOAD_VTABLE ((GCObject
*)cur
);
661 if (cur
> hole_start
)
662 SGEN_LOG (0, "HOLE [%p %p %d]", hole_start
, cur
, (int)(cur
- hole_start
));
663 SGEN_LOG (0, "OBJ [%p %p %d %d %s.%s %d]", cur
, cur
+ size
, (int)size
, (int)ss
,
664 sgen_client_vtable_get_namespace (vtable
), sgen_client_vtable_get_name (vtable
),
667 if (nursery_canaries_enabled () && !is_array_fill
) {
668 CHECK_CANARY_FOR_OBJECT ((GCObject
*)cur
, TRUE
);
669 CANARIFY_SIZE (size
);
677 * Checks that no objects in the nursery are fowarded or pinned. This
678 * is a precondition to restarting the mutator while doing a
679 * concurrent collection. Note that we don't clear fragments because
680 * we depend on that having happened earlier.
683 sgen_debug_check_nursery_is_clean (void)
687 cur
= sgen_get_nursery_start ();
688 end
= sgen_get_nursery_end ();
694 cur
+= sizeof (void*);
698 g_assert (!object_is_forwarded (cur
));
699 g_assert (!object_is_pinned (cur
));
701 size
= SGEN_ALIGN_UP (safe_object_get_size ((GCObject
*)cur
));
702 verify_scan_starts (cur
, cur
+ size
);
708 static gboolean scan_object_for_specific_ref_precise
= TRUE
;
711 #define HANDLE_PTR(ptr,obj) do { \
712 if ((GCObject*)*(ptr) == key) { \
713 GCVTable vtable = SGEN_LOAD_VTABLE (*(ptr)); \
714 g_print ("found ref to %p in object %p (%s.%s) at offset %zd\n", \
715 key, (obj), sgen_client_vtable_get_namespace (vtable), sgen_client_vtable_get_name (vtable), ((char*)(ptr) - (char*)(obj))); \
720 scan_object_for_specific_ref (GCObject
*obj
, GCObject
*key
)
724 if ((forwarded
= SGEN_OBJECT_IS_FORWARDED (obj
)))
727 if (scan_object_for_specific_ref_precise
) {
728 char *start
= (char*)obj
;
729 SgenDescriptor desc
= sgen_obj_get_descriptor_safe (obj
);
730 #include "sgen-scan-object.h"
732 mword
*words
= (mword
*)obj
;
733 size_t size
= safe_object_get_size (obj
);
735 for (i
= 0; i
< size
/ sizeof (mword
); ++i
) {
736 if (words
[i
] == (mword
)key
) {
737 GCVTable vtable
= SGEN_LOAD_VTABLE (obj
);
738 g_print ("found possible ref to %p in object %p (%s.%s) at offset %zd\n",
739 key
, obj
, sgen_client_vtable_get_namespace (vtable
), sgen_client_vtable_get_name (vtable
), i
* sizeof (mword
));
746 scan_object_for_specific_ref_callback (GCObject
*obj
, size_t size
, GCObject
*key
)
748 scan_object_for_specific_ref (obj
, key
);
752 check_root_obj_specific_ref (RootRecord
*root
, GCObject
*key
, GCObject
*obj
)
756 g_print ("found ref to %p in root record %p\n", key
, root
);
759 static GCObject
*check_key
= NULL
;
760 static RootRecord
*check_root
= NULL
;
763 check_root_obj_specific_ref_from_marker (GCObject
**obj
, void *gc_data
)
765 check_root_obj_specific_ref (check_root
, check_key
, *obj
);
769 scan_roots_for_specific_ref (GCObject
*key
, int root_type
)
775 SGEN_HASH_TABLE_FOREACH (&roots_hash
[root_type
], void **, start_root
, RootRecord
*, root
) {
776 SgenDescriptor desc
= root
->root_desc
;
780 switch (desc
& ROOT_DESC_TYPE_MASK
) {
781 case ROOT_DESC_BITMAP
:
782 desc
>>= ROOT_DESC_TYPE_SHIFT
;
785 check_root_obj_specific_ref (root
, key
, (GCObject
*)*start_root
);
790 case ROOT_DESC_COMPLEX
: {
791 gsize
*bitmap_data
= (gsize
*)sgen_get_complex_descriptor_bitmap (desc
);
792 int bwords
= (int) ((*bitmap_data
) - 1);
793 void **start_run
= start_root
;
795 while (bwords
-- > 0) {
796 gsize bmap
= *bitmap_data
++;
797 void **objptr
= start_run
;
800 check_root_obj_specific_ref (root
, key
, (GCObject
*)*objptr
);
804 start_run
+= GC_BITS_PER_WORD
;
808 case ROOT_DESC_VECTOR
: {
811 for (p
= start_root
; p
< (void**)root
->end_root
; p
++) {
813 check_root_obj_specific_ref (root
, key
, (GCObject
*)*p
);
817 case ROOT_DESC_USER
: {
818 SgenUserRootMarkFunc marker
= sgen_get_user_descriptor_func (desc
);
819 marker (start_root
, check_root_obj_specific_ref_from_marker
, NULL
);
822 case ROOT_DESC_RUN_LEN
:
823 g_assert_not_reached ();
825 g_assert_not_reached ();
827 } SGEN_HASH_TABLE_FOREACH_END
;
834 mono_gc_scan_for_specific_ref (GCObject
*key
, gboolean precise
)
839 scan_object_for_specific_ref_precise
= precise
;
841 sgen_scan_area_with_callback (nursery_section
->data
, nursery_section
->end_data
,
842 (IterateObjectCallbackFunc
)scan_object_for_specific_ref_callback
, key
, TRUE
, FALSE
);
844 major_collector
.iterate_objects (ITERATE_OBJECTS_SWEEP_ALL
, (IterateObjectCallbackFunc
)scan_object_for_specific_ref_callback
, key
);
846 sgen_los_iterate_objects ((IterateObjectCallbackFunc
)scan_object_for_specific_ref_callback
, key
);
848 scan_roots_for_specific_ref (key
, ROOT_TYPE_NORMAL
);
849 scan_roots_for_specific_ref (key
, ROOT_TYPE_WBARRIER
);
851 SGEN_HASH_TABLE_FOREACH (&roots_hash
[ROOT_TYPE_PINNED
], void **, ptr
, RootRecord
*, root
) {
852 while (ptr
< (void**)root
->end_root
) {
853 check_root_obj_specific_ref (root
, (GCObject
*)*ptr
, key
);
856 } SGEN_HASH_TABLE_FOREACH_END
;
858 if (sgen_is_world_stopped ())
859 find_pinning_ref_from_thread ((char*)key
, sizeof (GCObject
));
862 #ifndef SGEN_WITHOUT_MONO
864 static MonoDomain
*check_domain
= NULL
;
867 check_obj_not_in_domain (MonoObject
**o
)
869 g_assert (((*o
))->vtable
->domain
!= check_domain
);
874 check_obj_not_in_domain_callback (GCObject
**o
, void *gc_data
)
876 g_assert ((*o
)->vtable
->domain
!= check_domain
);
880 sgen_scan_for_registered_roots_in_domain (MonoDomain
*domain
, int root_type
)
884 check_domain
= domain
;
885 SGEN_HASH_TABLE_FOREACH (&roots_hash
[root_type
], void **, start_root
, RootRecord
*, root
) {
886 SgenDescriptor desc
= root
->root_desc
;
888 /* The MonoDomain struct is allowed to hold
889 references to objects in its own domain. */
890 if (start_root
== (void**)domain
)
893 switch (desc
& ROOT_DESC_TYPE_MASK
) {
894 case ROOT_DESC_BITMAP
:
895 desc
>>= ROOT_DESC_TYPE_SHIFT
;
897 if ((desc
& 1) && *start_root
)
898 check_obj_not_in_domain ((MonoObject
**)*start_root
);
903 case ROOT_DESC_COMPLEX
: {
904 gsize
*bitmap_data
= (gsize
*)sgen_get_complex_descriptor_bitmap (desc
);
905 int bwords
= (int)((*bitmap_data
) - 1);
906 void **start_run
= start_root
;
908 while (bwords
-- > 0) {
909 gsize bmap
= *bitmap_data
++;
910 void **objptr
= start_run
;
912 if ((bmap
& 1) && *objptr
)
913 check_obj_not_in_domain ((MonoObject
**)*objptr
);
917 start_run
+= GC_BITS_PER_WORD
;
921 case ROOT_DESC_VECTOR
: {
924 for (p
= start_root
; p
< (void**)root
->end_root
; p
++) {
926 check_obj_not_in_domain ((MonoObject
**)*p
);
930 case ROOT_DESC_USER
: {
931 SgenUserRootMarkFunc marker
= sgen_get_user_descriptor_func (desc
);
932 marker (start_root
, check_obj_not_in_domain_callback
, NULL
);
935 case ROOT_DESC_RUN_LEN
:
936 g_assert_not_reached ();
938 g_assert_not_reached ();
940 } SGEN_HASH_TABLE_FOREACH_END
;
946 is_xdomain_ref_allowed (GCObject
**ptr
, GCObject
*obj
, MonoDomain
*domain
)
948 MonoObject
*o
= (MonoObject
*)(obj
);
949 MonoObject
*ref
= *ptr
;
950 size_t offset
= (char*)(ptr
) - (char*)o
;
952 if (o
->vtable
->klass
== mono_defaults
.thread_class
&& offset
== G_STRUCT_OFFSET (MonoThread
, internal_thread
))
954 if (o
->vtable
->klass
== mono_defaults
.internal_thread_class
&& offset
== G_STRUCT_OFFSET (MonoInternalThread
, current_appcontext
))
957 #ifndef DISABLE_REMOTING
958 if (mono_defaults
.real_proxy_class
->supertypes
&& mono_class_has_parent_fast (o
->vtable
->klass
, mono_defaults
.real_proxy_class
) &&
959 offset
== G_STRUCT_OFFSET (MonoRealProxy
, unwrapped_server
))
963 * at System.IO.MemoryStream.InternalConstructor (byte[],int,int,bool,bool) [0x0004d] in /home/schani/Work/novell/trunk/mcs/class/corlib/System.IO/MemoryStream.cs:121
964 * at System.IO.MemoryStream..ctor (byte[]) [0x00017] in /home/schani/Work/novell/trunk/mcs/class/corlib/System.IO/MemoryStream.cs:81
965 * at (wrapper remoting-invoke-with-check) System.IO.MemoryStream..ctor (byte[]) <IL 0x00020, 0xffffffff>
966 * at System.Runtime.Remoting.Messaging.CADMethodCallMessage.GetArguments () [0x0000d] in /home/schani/Work/novell/trunk/mcs/class/corlib/System.Runtime.Remoting.Messaging/CADMessages.cs:327
967 * at System.Runtime.Remoting.Messaging.MethodCall..ctor (System.Runtime.Remoting.Messaging.CADMethodCallMessage) [0x00017] in /home/schani/Work/novell/trunk/mcs/class/corlib/System.Runtime.Remoting.Messaging/MethodCall.cs:87
968 * at System.AppDomain.ProcessMessageInDomain (byte[],System.Runtime.Remoting.Messaging.CADMethodCallMessage,byte[]&,System.Runtime.Remoting.Messaging.CADMethodReturnMessage&) [0x00018] in /home/schani/Work/novell/trunk/mcs/class/corlib/System/AppDomain.cs:1213
969 * at (wrapper remoting-invoke-with-check) System.AppDomain.ProcessMessageInDomain (byte[],System.Runtime.Remoting.Messaging.CADMethodCallMessage,byte[]&,System.Runtime.Remoting.Messaging.CADMethodReturnMessage&) <IL 0x0003d, 0xffffffff>
970 * at System.Runtime.Remoting.Channels.CrossAppDomainSink.ProcessMessageInDomain (byte[],System.Runtime.Remoting.Messaging.CADMethodCallMessage) [0x00008] in /home/schani/Work/novell/trunk/mcs/class/corlib/System.Runtime.Remoting.Channels/CrossAppDomainChannel.cs:198
971 * at (wrapper runtime-invoke) object.runtime_invoke_CrossAppDomainSink/ProcessMessageRes_object_object (object,intptr,intptr,intptr) <IL 0x0004c, 0xffffffff>
973 if (!strcmp (ref
->vtable
->klass
->name_space
, "System") &&
974 !strcmp (ref
->vtable
->klass
->name
, "Byte[]") &&
975 !strcmp (o
->vtable
->klass
->name_space
, "System.IO") &&
976 !strcmp (o
->vtable
->klass
->name
, "MemoryStream"))
982 check_reference_for_xdomain (GCObject
**ptr
, GCObject
*obj
, MonoDomain
*domain
)
984 MonoObject
*ref
= *ptr
;
985 size_t offset
= (char*)(ptr
) - (char*)obj
;
987 MonoClassField
*field
;
990 if (!ref
|| ref
->vtable
->domain
== domain
)
992 if (is_xdomain_ref_allowed (ptr
, obj
, domain
))
996 for (klass
= obj
->vtable
->klass
; klass
; klass
= klass
->parent
) {
999 int fcount
= mono_class_get_field_count (klass
);
1000 for (i
= 0; i
< fcount
; ++i
) {
1001 if (klass
->fields
[i
].offset
== offset
) {
1002 field
= &klass
->fields
[i
];
1010 if (ref
->vtable
->klass
== mono_defaults
.string_class
) {
1012 str
= mono_string_to_utf8_checked ((MonoString
*)ref
, &error
);
1013 mono_error_cleanup (&error
);
1016 g_print ("xdomain reference in %p (%s.%s) at offset %d (%s) to %p (%s.%s) (%s) - pointed to by:\n",
1017 obj
, obj
->vtable
->klass
->name_space
, obj
->vtable
->klass
->name
,
1018 offset
, field
? field
->name
: "",
1019 ref
, ref
->vtable
->klass
->name_space
, ref
->vtable
->klass
->name
, str
? str
: "");
1020 mono_gc_scan_for_specific_ref (obj
, TRUE
);
1026 #define HANDLE_PTR(ptr,obj) check_reference_for_xdomain ((ptr), (obj), domain)
1029 scan_object_for_xdomain_refs (GCObject
*obj
, mword size
, void *data
)
1031 char *start
= (char*)obj
;
1032 MonoVTable
*vt
= SGEN_LOAD_VTABLE (obj
);
1033 MonoDomain
*domain
= vt
->domain
;
1034 SgenDescriptor desc
= sgen_vtable_get_descriptor (vt
);
1036 #include "sgen-scan-object.h"
1040 sgen_check_for_xdomain_refs (void)
1044 sgen_scan_area_with_callback (nursery_section
->data
, nursery_section
->end_data
,
1045 (IterateObjectCallbackFunc
)scan_object_for_xdomain_refs
, NULL
, FALSE
, TRUE
);
1047 major_collector
.iterate_objects (ITERATE_OBJECTS_SWEEP_ALL
, (IterateObjectCallbackFunc
)scan_object_for_xdomain_refs
, NULL
);
1049 for (bigobj
= los_object_list
; bigobj
; bigobj
= bigobj
->next
)
1050 scan_object_for_xdomain_refs ((GCObject
*)bigobj
->data
, sgen_los_object_size (bigobj
), NULL
);
1055 /* If not null, dump the heap after each collection into this file */
1056 static FILE *heap_dump_file
= NULL
;
1059 sgen_dump_occupied (char *start
, char *end
, char *section_start
)
1061 fprintf (heap_dump_file
, "<occupied offset=\"%zd\" size=\"%zd\"/>\n", start
- section_start
, end
- start
);
1065 sgen_dump_section (GCMemSection
*section
, const char *type
)
1067 char *start
= section
->data
;
1068 char *end
= section
->end_data
;
1069 char *occ_start
= NULL
;
1071 fprintf (heap_dump_file
, "<section type=\"%s\" size=\"%lu\">\n", type
, (unsigned long)(section
->end_data
- section
->data
));
1073 while (start
< end
) {
1078 if (!*(void**)start
) {
1080 sgen_dump_occupied (occ_start
, start
, section
->data
);
1083 start
+= sizeof (void*); /* should be ALLOC_ALIGN, really */
1090 //vt = SGEN_LOAD_VTABLE (start);
1091 //class = vt->klass;
1093 size
= SGEN_ALIGN_UP (safe_object_get_size ((GCObject
*) start
));
1096 fprintf (heap_dump_file, "<object offset=\"%d\" class=\"%s.%s\" size=\"%d\"/>\n",
1097 start - section->data,
1098 vt->klass->name_space, vt->klass->name,
1105 sgen_dump_occupied (occ_start
, start
, section
->data
);
1107 fprintf (heap_dump_file
, "</section>\n");
1111 dump_object (GCObject
*obj
, gboolean dump_location
)
1113 #ifndef SGEN_WITHOUT_MONO
1114 static char class_name
[1024];
1116 MonoClass
*klass
= mono_object_class (obj
);
1120 * Python's XML parser is too stupid to parse angle brackets
1121 * in strings, so we just ignore them;
1124 while (klass
->name
[i
] && j
< sizeof (class_name
) - 1) {
1125 if (!strchr ("<>\"", klass
->name
[i
]))
1126 class_name
[j
++] = klass
->name
[i
];
1129 g_assert (j
< sizeof (class_name
));
1132 fprintf (heap_dump_file
, "<object class=\"%s.%s\" size=\"%zd\"",
1133 klass
->name_space
, class_name
,
1134 safe_object_get_size (obj
));
1135 if (dump_location
) {
1136 const char *location
;
1137 if (sgen_ptr_in_nursery (obj
))
1138 location
= "nursery";
1139 else if (safe_object_get_size (obj
) <= SGEN_MAX_SMALL_OBJ_SIZE
)
1143 fprintf (heap_dump_file
, " location=\"%s\"", location
);
1145 fprintf (heap_dump_file
, "/>\n");
1150 sgen_debug_enable_heap_dump (const char *filename
)
1152 heap_dump_file
= fopen (filename
, "w");
1153 if (heap_dump_file
) {
1154 fprintf (heap_dump_file
, "<sgen-dump>\n");
1155 sgen_pin_stats_enable ();
1160 sgen_debug_dump_heap (const char *type
, int num
, const char *reason
)
1162 SgenPointerQueue
*pinned_objects
;
1166 if (!heap_dump_file
)
1169 fprintf (heap_dump_file
, "<collection type=\"%s\" num=\"%d\"", type
, num
);
1171 fprintf (heap_dump_file
, " reason=\"%s\"", reason
);
1172 fprintf (heap_dump_file
, ">\n");
1173 #ifndef SGEN_WITHOUT_MONO
1174 fprintf (heap_dump_file
, "<other-mem-usage type=\"mempools\" size=\"%ld\"/>\n", mono_mempool_get_bytes_allocated ());
1176 sgen_dump_internal_mem_usage (heap_dump_file
);
1177 fprintf (heap_dump_file
, "<pinned type=\"stack\" bytes=\"%zu\"/>\n", sgen_pin_stats_get_pinned_byte_count (PIN_TYPE_STACK
));
1178 /* fprintf (heap_dump_file, "<pinned type=\"static-data\" bytes=\"%d\"/>\n", pinned_byte_counts [PIN_TYPE_STATIC_DATA]); */
1179 fprintf (heap_dump_file
, "<pinned type=\"other\" bytes=\"%zu\"/>\n", sgen_pin_stats_get_pinned_byte_count (PIN_TYPE_OTHER
));
1181 fprintf (heap_dump_file
, "<pinned-objects>\n");
1182 pinned_objects
= sgen_pin_stats_get_object_list ();
1183 for (i
= 0; i
< pinned_objects
->next_slot
; ++i
)
1184 dump_object ((GCObject
*)pinned_objects
->data
[i
], TRUE
);
1185 fprintf (heap_dump_file
, "</pinned-objects>\n");
1187 sgen_dump_section (nursery_section
, "nursery");
1189 major_collector
.dump_heap (heap_dump_file
);
1191 fprintf (heap_dump_file
, "<los>\n");
1192 for (bigobj
= los_object_list
; bigobj
; bigobj
= bigobj
->next
)
1193 dump_object ((GCObject
*)bigobj
->data
, FALSE
);
1194 fprintf (heap_dump_file
, "</los>\n");
1196 fprintf (heap_dump_file
, "</collection>\n");
1199 static GCObject
*found_obj
;
1202 find_object_for_ptr_callback (GCObject
*obj
, size_t size
, void *user_data
)
1204 char *ptr
= (char *)user_data
;
1206 if (ptr
>= (char*)obj
&& ptr
< (char*)obj
+ size
) {
1207 g_assert (!found_obj
);
1212 /* for use in the debugger */
1214 sgen_find_object_for_ptr (char *ptr
)
1216 if (ptr
>= nursery_section
->data
&& ptr
< nursery_section
->end_data
) {
1218 sgen_scan_area_with_callback (nursery_section
->data
, nursery_section
->end_data
,
1219 find_object_for_ptr_callback
, ptr
, TRUE
, FALSE
);
1225 sgen_los_iterate_objects (find_object_for_ptr_callback
, ptr
);
1230 * Very inefficient, but this is debugging code, supposed to
1231 * be called from gdb, so we don't care.
1234 major_collector
.iterate_objects (ITERATE_OBJECTS_SWEEP_ALL
, find_object_for_ptr_callback
, ptr
);
1238 #endif /*HAVE_SGEN_GC*/