[xbuild] Vbc task - make error column check a little non-specific.
[mono.git] / mono / mini / mini-gc.c
index 0dc7f7f64d936b6ab9d0e099ff5e779fc6fd442d..3972f5730972f70359077abf0ee3aa51bedd0ed5 100644 (file)
 #include <mono/metadata/gc-internal.h>
 
 //#if 0
-#ifdef HAVE_SGEN_GC
+#if defined(MONO_ARCH_GC_MAPS_SUPPORTED)
 
 #include <mono/metadata/gc-internal.h>
 #include <mono/utils/mono-counters.h>
 
+#if SIZEOF_VOID_P == 4
+typedef guint32 mword;
+#else
+typedef guint64 mword;
+#endif
+
+#define GC_BITS_PER_WORD (sizeof (mword) * 8)
+
 /* Contains state needed by the GC Map construction code */
 typedef struct {
        /*
@@ -64,23 +72,26 @@ typedef struct {
        guint8 *reg_pin_bitmap;
 } MonoCompileGC;
 
-#define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
+#define ALIGN_TO(val,align) ((((mgreg_t)val) + ((align) - 1)) & ~((align) - 1))
+
+#undef DEBUG
 
 #if 0
-#define DEBUG(s) do { s; } while (0)
+/* We don't support debug levels, its all-or-nothing */
+#define DEBUG(s) do { s; fflush (logfile); } while (0)
 #define DEBUG_ENABLED 1
 #else
 #define DEBUG(s)
 #endif
 
-#if 1
-#define DEBUG_GC_MAP(s) do { s; fflush (stdout); } while (0)
+#ifdef DEBUG_ENABLED
+//#if 1
+#define DEBUG_PRECISE(s) do { s; } while (0)
+#define DEBUG_PRECISE_ENABLED
 #else
-#define DEBUG_GC_MAP(s)
+#define DEBUG_PRECISE(s)
 #endif
 
-#define GC_BITS_PER_WORD (sizeof (gsize) * 8)
-
 /*
  * Contains information collected during the conservative stack marking pass,
  * used during the precise pass. This helps to avoid doing a stack walk twice, which
@@ -93,7 +104,7 @@ typedef struct {
        int nreg_locations;
        /* Relative to stack_start */
        int reg_locations [MONO_MAX_IREGS];
-#ifdef DEBUG_ENABLED
+#ifdef DEBUG_PRECISE_ENABLED
        MonoJitInfo *ji;
        gpointer fp;
        int regs [MONO_MAX_IREGS];
@@ -114,7 +125,8 @@ typedef struct {
        gboolean has_context;
        MonoJitTlsData *jit_tls;
        /* For debugging */
-       guint64 tid;
+       mgreg_t tid;
+       gpointer ref_to_track;
        /* Number of frames collected during the !precise pass */
        int nframes;
        FrameInfo frames [MAX_FRAMES];
@@ -247,6 +259,8 @@ typedef struct {
 
 static JITGCStats stats;
 
+static FILE *logfile;
+
 // FIXME: Move these to a shared place
 
 static inline void
@@ -351,6 +365,11 @@ encode_frame_reg (int frame_reg)
                return 0;
        else if (frame_reg == AMD64_RBP)
                return 1;
+#elif defined(TARGET_X86)
+       if (frame_reg == X86_EBP)
+               return 0;
+       else if (frame_reg == X86_ESP)
+               return 1;
 #else
        NOT_IMPLEMENTED;
 #endif
@@ -366,6 +385,11 @@ decode_frame_reg (int encoded)
                return AMD64_RSP;
        else if (encoded == 1)
                return AMD64_RBP;
+#elif defined(TARGET_X86)
+       if (encoded == 0)
+               return X86_EBP;
+       else if (encoded == 1)
+               return X86_ESP;
 #else
        NOT_IMPLEMENTED;
 #endif
@@ -379,12 +403,13 @@ static int callee_saved_regs [] = { AMD64_RBP, AMD64_RBX, AMD64_R12, AMD64_R13,
 #else
 static int callee_saved_regs [] = { AMD64_RBP, AMD64_RBX, AMD64_R12, AMD64_R13, AMD64_R14, AMD64_R15 };
 #endif
+#elif defined(TARGET_X86)
+static int callee_saved_regs [] = { X86_EBX, X86_ESI, X86_EDI };
 #endif
 
 static guint32
 encode_regmask (guint32 regmask)
 {
-#ifdef TARGET_AMD64
        int i;
        guint32 res;
 
@@ -397,16 +422,11 @@ encode_regmask (guint32 regmask)
        }
        g_assert (regmask == 0);
        return res;
-#else
-       NOT_IMPLEMENTED;
-       return regmask;
-#endif
 }
 
 static guint32
 decode_regmask (guint32 regmask)
 {
-#ifdef TARGET_AMD64
        int i;
        guint32 res;
 
@@ -415,10 +435,6 @@ decode_regmask (guint32 regmask)
                if (regmask & (1 << i))
                        res |= (1 << callee_saved_regs [i]);
        return res;
-#else
-       NOT_IMPLEMENTED;
-       return regmask;
-#endif
 }
 
 /*
@@ -588,6 +604,24 @@ slot_type_to_string (GCSlotType type)
        }
 }
 
+static inline mgreg_t
+get_frame_pointer (MonoContext *ctx, int frame_reg)
+{
+#if defined(TARGET_AMD64)
+               if (frame_reg == AMD64_RSP)
+                       return ctx->rsp;
+               else if (frame_reg == AMD64_RBP)
+                       return ctx->rbp;
+#elif defined(TARGET_X86)
+               if (frame_reg == X86_ESP)
+                       return ctx->esp;
+               else if (frame_reg == X86_EBP)
+                       return ctx->ebp;
+#endif
+               g_assert_not_reached ();
+               return 0;
+}
+
 /*
  * conservatively_pass:
  *
@@ -615,6 +649,11 @@ conservative_pass (TlsData *tls, guint8 *stack_start, guint8 *stack_end)
        FrameInfo *fi;
        guint32 precise_regmask;
 
+       if (tls) {
+               tls->nframes = 0;
+               tls->ref_to_track = NULL;
+       }
+
        /* tls == NULL can happen during startup */
        if (mono_thread_internal_current () == NULL || !tls) {
                mono_gc_conservatively_scan_area (stack_start, stack_end);
@@ -645,8 +684,6 @@ conservative_pass (TlsData *tls, guint8 *stack_start, guint8 *stack_end)
        memset (reg_locations, 0, sizeof (reg_locations));
        memset (new_reg_locations, 0, sizeof (new_reg_locations));
 
-       tls->nframes = 0;
-
        while (TRUE) {
                memcpy (&ctx, &new_ctx, sizeof (ctx));
 
@@ -658,43 +695,62 @@ conservative_pass (TlsData *tls, guint8 *stack_start, guint8 *stack_end)
                                 * we have to mark it conservatively.
                                 */
                                if (reg_locations [i]) {
-                                       DEBUG (printf ("\tscan saved reg %s location %p.\n", mono_arch_regname (i), reg_locations [i]));
+                                       DEBUG (fprintf (logfile, "\tscan saved reg %s location %p.\n", mono_arch_regname (i), reg_locations [i]));
                                        mono_gc_conservatively_scan_area (reg_locations [i], reg_locations [i] + sizeof (mgreg_t));
                                        scanned_registers += sizeof (mgreg_t);
                                }
 
                                reg_locations [i] = new_reg_locations [i];
 
-                               DEBUG (printf ("\treg %s is now at location %p.\n", mono_arch_regname (i), reg_locations [i]));
+                               DEBUG (fprintf (logfile, "\treg %s is now at location %p.\n", mono_arch_regname (i), reg_locations [i]));
                        }
                }
 
-               g_assert ((guint64)stack_limit % sizeof (mgreg_t) == 0);
+               g_assert ((mgreg_t)stack_limit % sizeof (mgreg_t) == 0);
 
-#ifdef MONO_ARCH_HAVE_FIND_JIT_INFO_EXT
                res = mono_find_jit_info_ext (frame.domain ? frame.domain : mono_domain_get (), tls->jit_tls, NULL, &ctx, &new_ctx, NULL, &lmf, new_reg_locations, &frame);
                if (!res)
                        break;
-#else
-               break;
-#endif
+
+               ji = frame.ji;
+
+               if (frame.type == FRAME_TYPE_MANAGED_TO_NATIVE) {
+                       /*
+                        * These frames are problematic for several reasons:
+                        * - they are unwound through an LMF, and we have no precise register tracking for those.
+                        * - the LMF might not contain a precise ip, so we can't compute the call site.
+                        * - the LMF only unwinds to the wrapper frame, so we get these methods twice.
+                        */
+                       DEBUG (fprintf (logfile, "Mark(0): <Managed-to-native transition>\n"));
+                       for (i = 0; i < MONO_MAX_IREGS; ++i) {
+                               if (reg_locations [i]) {
+                                       DEBUG (fprintf (logfile, "\tscan saved reg %s location %p.\n", mono_arch_regname (i), reg_locations [i]));
+                                       mono_gc_conservatively_scan_area (reg_locations [i], reg_locations [i] + sizeof (mgreg_t));
+                                       scanned_registers += sizeof (mgreg_t);
+                               }
+                               reg_locations [i] = NULL;
+                               new_reg_locations [i] = NULL;
+                       }
+                       ctx = new_ctx;
+                       continue;
+               }
 
                /* The last frame can be in any state so mark conservatively */
                if (last) {
+                       if (ji) {
+                               DEBUG (char *fname = mono_method_full_name (ji->method, TRUE); fprintf (logfile, "Mark(0): %s+0x%x (%p)\n", fname, pc_offset, (gpointer)MONO_CONTEXT_GET_IP (&ctx)); g_free (fname));
+                       }
+                       DEBUG (fprintf (logfile, "\t <Last frame>\n"));
                        last = FALSE;
                        continue;
                }
 
-               ji = frame.ji;
-
-               /* This happens with native-to-managed transitions */
-               if (!(MONO_CONTEXT_GET_IP (&ctx) >= ji->code_start && (guint8*)MONO_CONTEXT_GET_IP (&ctx) < (guint8*)ji->code_start + ji->code_size))
-                       continue;
+               pc_offset = (guint8*)MONO_CONTEXT_GET_IP (&ctx) - (guint8*)ji->code_start;
 
                /* These frames are very problematic */
                if (ji->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
-                       DEBUG (char *fname = mono_method_full_name (ji->method, TRUE); printf ("Mark(0): %s+0x%x (%p)\n", fname, pc_offset, (gpointer)MONO_CONTEXT_GET_IP (&ctx)); g_free (fname));
-                       DEBUG (printf ("\tSkip.\n"));
+                       DEBUG (char *fname = mono_method_full_name (ji->method, TRUE); fprintf (logfile, "Mark(0): %s+0x%x (%p)\n", fname, pc_offset, (gpointer)MONO_CONTEXT_GET_IP (&ctx)); g_free (fname));
+                       DEBUG (fprintf (logfile, "\tSkip.\n"));
                        continue;
                }
 
@@ -705,7 +761,7 @@ conservative_pass (TlsData *tls, guint8 *stack_start, guint8 *stack_end)
                         * Can't save information since the array is full. So scan the rest of the
                         * stack conservatively.
                         */
-                       DEBUG (printf ("Mark (0): Frame stack full.\n"));
+                       DEBUG (fprintf (logfile, "Mark (0): Frame stack full.\n"));
                        break;
                }
 
@@ -719,17 +775,19 @@ conservative_pass (TlsData *tls, guint8 *stack_start, guint8 *stack_end)
                 * - spill area
                 * - localloc-ed memory
                 */
-               pc_offset = (guint8*)MONO_CONTEXT_GET_IP (&ctx) - (guint8*)ji->code_start;
                g_assert (pc_offset >= 0);
 
                emap = ji->gc_info;
 
                if (!emap) {
-                       DEBUG (char *fname = mono_method_full_name (ji->method, TRUE); printf ("Mark(0): %s+0x%x (%p)\n", fname, pc_offset, (gpointer)MONO_CONTEXT_GET_IP (&ctx)); g_free (fname));
-                       DEBUG (printf ("\tNo GC Map.\n"));
+                       DEBUG (char *fname = mono_method_full_name (ji->method, TRUE); fprintf (logfile, "Mark(0): %s+0x%x (%p)\n", fname, pc_offset, (gpointer)MONO_CONTEXT_GET_IP (&ctx)); g_free (fname));
+                       DEBUG (fprintf (logfile, "\tNo GC Map.\n"));
                        continue;
                }
 
+               /* The embedded callsite table requires this */
+               g_assert (((mgreg_t)emap % 4) == 0);
+
                /*
                 * Debugging aid to control the number of frames scanned precisely
                 */
@@ -756,31 +814,21 @@ conservative_pass (TlsData *tls, guint8 *stack_start, guint8 *stack_end)
                p += map->callsite_entry_size * map->ncallsites;
                bitmaps = p;
 
-#ifdef __x86_64__
-               if (map->frame_reg == AMD64_RSP)
-                       fp = (guint8*)ctx.rsp;
-               else if (map->frame_reg == AMD64_RBP)
-                       fp = (guint8*)ctx.rbp;
-               else
-                       g_assert_not_reached ();
-#else
-               fp = NULL;
-               g_assert_not_reached ();
-#endif
+               fp = (guint8*)get_frame_pointer (&ctx, map->frame_reg);
 
                real_frame_start = fp + map->start_offset;
                frame_start = fp + map->start_offset + map->map_offset;
                frame_end = fp + map->end_offset;
 
-               DEBUG (char *fname = mono_method_full_name (ji->method, TRUE); printf ("Mark(0): %s+0x%x (%p) limit=%p fp=%p frame=%p-%p (%d)\n", fname, pc_offset, (gpointer)MONO_CONTEXT_GET_IP (&ctx), stack_limit, fp, frame_start, frame_end, (int)(frame_end - frame_start)); g_free (fname));
+               DEBUG (char *fname = mono_method_full_name (ji->method, TRUE); fprintf (logfile, "Mark(0): %s+0x%x (%p) limit=%p fp=%p frame=%p-%p (%d)\n", fname, pc_offset, (gpointer)MONO_CONTEXT_GET_IP (&ctx), stack_limit, fp, frame_start, frame_end, (int)(frame_end - frame_start)); g_free (fname));
 
                /* Find the callsite index */
-               if (ji->code_size < 256) {
+               if (map->callsite_entry_size == 1) {
                        for (i = 0; i < map->ncallsites; ++i)
                                /* ip points inside the call instruction */
                                if (map->callsites.offsets8 [i] == pc_offset + 1)
                                        break;
-               } else if (ji->code_size < 65536) {
+               } else if (map->callsite_entry_size == 2) {
                        // FIXME: Use a binary search
                        for (i = 0; i < map->ncallsites; ++i)
                                /* ip points inside the call instruction */
@@ -803,7 +851,7 @@ conservative_pass (TlsData *tls, guint8 *stack_start, guint8 *stack_end)
 
                if (real_frame_start > stack_limit) {
                        /* This scans the previously skipped frames as well */
-                       DEBUG (printf ("\tscan area %p-%p (%d).\n", stack_limit, real_frame_start, (int)(real_frame_start - stack_limit)));
+                       DEBUG (fprintf (logfile, "\tscan area %p-%p (%d).\n", stack_limit, real_frame_start, (int)(real_frame_start - stack_limit)));
                        mono_gc_conservatively_scan_area (stack_limit, real_frame_start);
                        stats.scanned_other += real_frame_start - stack_limit;
                }
@@ -819,7 +867,7 @@ conservative_pass (TlsData *tls, guint8 *stack_start, guint8 *stack_end)
                        for (i = 0; i < map->nslots; ++i) {
                                pinned = pin_bitmap [i / 8] & (1 << (i % 8));
                                if (pinned) {
-                                       DEBUG (printf ("\tscan slot %s0x%x(fp)=%p.\n", (guint8*)p > (guint8*)fp ? "" : "-", ABS ((int)((gssize)p - (gssize)fp)), p));
+                                       DEBUG (fprintf (logfile, "\tscan slot %s0x%x(fp)=%p.\n", (guint8*)p > (guint8*)fp ? "" : "-", ABS ((int)((gssize)p - (gssize)fp)), p));
                                        mono_gc_conservatively_scan_area (p, p + sizeof (mgreg_t));
                                        scanned_conservatively += sizeof (mgreg_t);
                                } else {
@@ -848,7 +896,7 @@ conservative_pass (TlsData *tls, guint8 *stack_start, guint8 *stack_end)
                                        continue;
 
                                if (pin_bitmap [bindex / 8] & (1 << (bindex % 8))) {
-                                       DEBUG (printf ("\treg %s saved at 0x%p is pinning.\n", mono_arch_regname (i), reg_locations [i]));
+                                       DEBUG (fprintf (logfile, "\treg %s saved at 0x%p is pinning.\n", mono_arch_regname (i), reg_locations [i]));
                                        precise_regmask &= ~(1 << i);
                                }
                                bindex ++;
@@ -871,8 +919,8 @@ conservative_pass (TlsData *tls, guint8 *stack_start, guint8 *stack_end)
                        fi->bitmap = NULL;
                fi->frame_start_offset = frame_start - stack_start;
                fi->nreg_locations = 0;
-               DEBUG (fi->ji = ji);
-               DEBUG (fi->fp = fp);
+               DEBUG_PRECISE (fi->ji = ji);
+               DEBUG_PRECISE (fi->fp = fp);
 
                if (map->has_ref_regs) {
                        int bitmap_width = ALIGN_TO (map->nref_regs, 8) / 8;
@@ -883,8 +931,8 @@ conservative_pass (TlsData *tls, guint8 *stack_start, guint8 *stack_end)
                                        continue;
 
                                if (reg_locations [i] && (ref_bitmap [bindex / 8] & (1 << (bindex % 8)))) {
-                                       DEBUG (fi->regs [fi->nreg_locations] = i);
-                                       DEBUG (printf ("\treg %s saved at 0x%p is ref.\n", mono_arch_regname (i), reg_locations [i]));
+                                       DEBUG_PRECISE (fi->regs [fi->nreg_locations] = i);
+                                       DEBUG (fprintf (logfile, "\treg %s saved at 0x%p is ref.\n", mono_arch_regname (i), reg_locations [i]));
                                        fi->reg_locations [fi->nreg_locations] = (guint8*)reg_locations [i] - stack_start;
                                        fi->nreg_locations ++;
                                }
@@ -905,7 +953,7 @@ conservative_pass (TlsData *tls, guint8 *stack_start, guint8 *stack_end)
                                         * processed.
                                         */
                                        if (reg_locations [i])
-                                               DEBUG (printf ("\treg %s at location %p (==%p) is precise.\n", mono_arch_regname (i), reg_locations [i], (gpointer)*reg_locations [i]));
+                                               DEBUG (fprintf (logfile, "\treg %s at location %p (==%p) is precise.\n", mono_arch_regname (i), reg_locations [i], (gpointer)*reg_locations [i]));
                                        reg_locations [i] = NULL;
                                }
                        }
@@ -917,24 +965,24 @@ conservative_pass (TlsData *tls, guint8 *stack_start, guint8 *stack_end)
        /* Scan the remaining register save locations */
        for (i = 0; i < MONO_MAX_IREGS; ++i) {
                if (reg_locations [i]) {
-                       DEBUG (printf ("\tscan saved reg location %p.\n", reg_locations [i]));
+                       DEBUG (fprintf (logfile, "\tscan saved reg location %p.\n", reg_locations [i]));
                        mono_gc_conservatively_scan_area (reg_locations [i], reg_locations [i] + sizeof (mgreg_t));
                        scanned_registers += sizeof (mgreg_t);
                }
                if (new_reg_locations [i]) {
-                       DEBUG (printf ("\tscan saved reg location %p.\n", new_reg_locations [i]));
+                       DEBUG (fprintf (logfile, "\tscan saved reg location %p.\n", new_reg_locations [i]));
                        mono_gc_conservatively_scan_area (new_reg_locations [i], new_reg_locations [i] + sizeof (mgreg_t));
                        scanned_registers += sizeof (mgreg_t);
                }
        }
 
        if (stack_limit < stack_end) {
-               DEBUG (printf ("\tscan remaining stack %p-%p (%d).\n", stack_limit, stack_end, (int)(stack_end - stack_limit)));
+               DEBUG (fprintf (logfile, "\tscan remaining stack %p-%p (%d).\n", stack_limit, stack_end, (int)(stack_end - stack_limit)));
                mono_gc_conservatively_scan_area (stack_limit, stack_end);
                stats.scanned_native += stack_end - stack_limit;
        }
 
-       DEBUG (printf ("Marked %d bytes, p=%d,c=%d out of %d.\n", scanned, scanned_precisely, scanned_conservatively, (int)(stack_end - stack_start)));
+       DEBUG (fprintf (logfile, "Marked %d bytes, p=%d,c=%d out of %d.\n", scanned, scanned_precisely, scanned_conservatively, (int)(stack_end - stack_start)));
 
        stats.scanned_stacks += stack_end - stack_start;
        stats.scanned += scanned;
@@ -966,6 +1014,8 @@ precise_pass (TlsData *tls, guint8 *stack_start, guint8 *stack_end)
                fi = &tls->frames [findex];
                frame_start = stack_start + fi->frame_start_offset;
 
+               DEBUG (char *fname = mono_method_full_name (fi->ji->method, TRUE); fprintf (logfile, "Mark(1): %s\n", fname); g_free (fname));
+
                /* 
                 * FIXME: Add a function to mark using a bitmap, to avoid doing a 
                 * call for each object.
@@ -984,11 +1034,11 @@ precise_pass (TlsData *tls, guint8 *stack_start, guint8 *stack_end)
                                if (live) {
                                        MonoObject *obj = *ptr;
                                        if (obj) {
-                                               DEBUG (printf ("\tref %s0x%x(fp)=%p: %p ->", (guint8*)ptr >= (guint8*)fi->fp ? "" : "-", ABS ((int)((gssize)ptr - (gssize)fi->fp)), ptr, obj));
+                                               DEBUG (fprintf (logfile, "\tref %s0x%x(fp)=%p: %p ->", (guint8*)ptr >= (guint8*)fi->fp ? "" : "-", ABS ((int)((gssize)ptr - (gssize)fi->fp)), ptr, obj));
                                                *ptr = mono_gc_scan_object (obj);
-                                               DEBUG (printf (" %p.\n", *ptr));
+                                               DEBUG (fprintf (logfile, " %p.\n", *ptr));
                                        } else {
-                                               DEBUG (printf ("\tref %s0x%x(fp)=%p: %p.\n", (guint8*)ptr >= (guint8*)fi->fp ? "" : "-", ABS ((int)((gssize)ptr - (gssize)fi->fp)), ptr, obj));
+                                               DEBUG (fprintf (logfile, "\tref %s0x%x(fp)=%p: %p.\n", (guint8*)ptr >= (guint8*)fi->fp ? "" : "-", ABS ((int)((gssize)ptr - (gssize)fi->fp)), ptr, obj));
                                        }
                                } else {
 #if 0
@@ -997,7 +1047,7 @@ precise_pass (TlsData *tls, guint8 *stack_start, guint8 *stack_end)
                                         * Stack slots might be shared between ref and non-ref variables ?
                                         */
                                        if (map->ref_slots [i / 8] & (1 << (i % 8))) {
-                                               DEBUG (printf ("\tref %s0x%x(fp)=%p: dead (%p)\n", (guint8*)ptr >= (guint8*)fi->fp ? "" : "-", ABS ((int)((gssize)ptr - (gssize)fi->fp)), ptr, *ptr));
+                                               DEBUG (fprintf (logfile, "\tref %s0x%x(fp)=%p: dead (%p)\n", (guint8*)ptr >= (guint8*)fi->fp ? "" : "-", ABS ((int)((gssize)ptr - (gssize)fi->fp)), ptr, *ptr));
                                                /*
                                                 * Fail fast if the live range is incorrect, and
                                                 * the JITted code tries to access this object
@@ -1025,14 +1075,25 @@ precise_pass (TlsData *tls, guint8 *stack_start, guint8 *stack_end)
                        MonoObject *obj = *ptr;
 
                        if (obj) {
-                               DEBUG (printf ("\treg %s saved at %p: %p ->", mono_arch_regname (fi->regs [i]), ptr, obj));
+                               DEBUG (fprintf (logfile, "\treg %s saved at %p: %p ->", mono_arch_regname (fi->regs [i]), ptr, obj));
                                *ptr = mono_gc_scan_object (obj);
-                               DEBUG (printf (" %p.\n", *ptr));
+                               DEBUG (fprintf (logfile, " %p.\n", *ptr));
                        } else {
-                               DEBUG (printf ("\treg %s saved at %p: %p", mono_arch_regname (fi->regs [i]), ptr, obj));
+                               DEBUG (fprintf (logfile, "\treg %s saved at %p: %p\n", mono_arch_regname (fi->regs [i]), ptr, obj));
                        }
                }       
        }
+
+       /*
+        * Debugging aid to check for missed refs.
+        */
+       if (tls->ref_to_track) {
+               mgreg_t *p;
+
+               for (p = (mgreg_t*)stack_start; p < (mgreg_t*)stack_end; ++p)
+                       if (*p == (mgreg_t)tls->ref_to_track)
+                               printf ("REF AT %p.\n", p);
+       }
 }
 
 /*
@@ -1047,7 +1108,9 @@ thread_mark_func (gpointer user_data, guint8 *stack_start, guint8 *stack_end, gb
 {
        TlsData *tls = user_data;
 
-       DEBUG (printf ("*** %s stack marking %p-%p ***\n", precise ? "Precise" : "Conservative", stack_start, stack_end));
+       DEBUG (fprintf (logfile, "****************************************\n"));
+       DEBUG (fprintf (logfile, "*** %s stack marking for thread %p (%p-%p) ***\n", precise ? "Precise" : "Conservative", tls ? GUINT_TO_POINTER (tls->tid) : NULL, stack_start, stack_end));
+       DEBUG (fprintf (logfile, "****************************************\n"));
 
        if (!precise)
                conservative_pass (tls, stack_start, stack_end);
@@ -1061,6 +1124,12 @@ mini_gc_init_gc_map (MonoCompile *cfg)
        if (COMPILE_LLVM (cfg))
                return;
 
+       if (!mono_gc_is_moving ())
+               return;
+
+       if (!cfg->compile_aot && !mono_gc_precise_stack_mark_enabled ())
+               return;
+
 #if 1
        /* Debugging support */
        {
@@ -1498,7 +1567,8 @@ process_variables (MonoCompile *cfg)
                                mono_class_compute_gc_descriptor (ins->klass);
 
                                bitmap = mono_gc_get_bitmap_for_descr (ins->klass->gc_descr, &numbits);
-                               g_assert (bitmap);
+                               if (!bitmap)
+                                       pin = TRUE;
 
                                /*
                                 * Most vtypes are marked volatile because of the LDADDR instructions,
@@ -1522,7 +1592,7 @@ process_variables (MonoCompile *cfg)
                                                for (j = 0; j < numbits; ++j) {
                                                        if (bitmap [j / GC_BITS_PER_WORD] & ((gsize)1 << (j % GC_BITS_PER_WORD))) {
                                                                /* The descriptor is for the boxed object */
-                                                               set_slot (gcfg, (pos + j - (sizeof (MonoObject) / sizeof (gpointer))), cindex, pin ? SLOT_PIN : SLOT_REF);
+                                                               set_slot (gcfg, (pos + j - (sizeof (MonoObject) / sizeof (mgreg_t))), cindex, pin ? SLOT_PIN : SLOT_REF);
                                                        }
                                                }
                                        }
@@ -1531,7 +1601,7 @@ process_variables (MonoCompile *cfg)
                                if (cfg->verbose_level > 1) {
                                        for (j = 0; j < numbits; ++j) {
                                                if (bitmap [j / GC_BITS_PER_WORD] & ((gsize)1 << (j % GC_BITS_PER_WORD)))
-                                                       printf ("\t\t%s slot at 0x%x(fp) (slot = %d)\n", pin ? "pin" : "ref", (int)(ins->inst_offset + (j * sizeof (mgreg_t))), (int)(pos + j - (sizeof (MonoObject) / sizeof (gpointer))));
+                                                       printf ("\t\t%s slot at 0x%x(fp) (slot = %d)\n", pin ? "pin" : "ref", (int)(ins->inst_offset + (j * sizeof (mgreg_t))), (int)(pos + j - (sizeof (MonoObject) / sizeof (mgreg_t))));
                                        }
                                }
                        } else {
@@ -1791,7 +1861,7 @@ compute_frame_size (MonoCompile *cfg)
        /* Compute min/max offsets from the fp */
 
        /* Locals */
-#ifdef TARGET_AMD64
+#if defined(TARGET_AMD64) || defined(TARGET_X86)
        locals_min_offset = ALIGN_TO (cfg->locals_min_stack_offset, sizeof (mgreg_t));
        locals_max_offset = cfg->locals_max_stack_offset;
 #else
@@ -2145,7 +2215,7 @@ create_map (MonoCompile *cfg)
                p += encoded_size;
 
                /* Callsite table */
-               p = (guint8*)ALIGN_TO ((guint64)p, map->callsite_entry_size);
+               p = (guint8*)ALIGN_TO ((mgreg_t)p, map->callsite_entry_size);
                if (map->callsite_entry_size == 1) {
                        guint8 *offsets = p;
                        for (i = 0; i < ncallsites; ++i)
@@ -2166,6 +2236,9 @@ create_map (MonoCompile *cfg)
 
                /* Bitmaps */
                memcpy (p, bitmaps, bitmaps_size);
+               p += bitmaps_size;
+
+               g_assert ((guint8*)p - (guint8*)emap <= alloc_size);
 
                stats.gc_maps_size += alloc_size;
                stats.gc_callsites_size += ncallsites * map->callsite_entry_size;
@@ -2173,6 +2246,9 @@ create_map (MonoCompile *cfg)
                stats.gc_map_struct_size += sizeof (GCEncodedMap) + encoded_size;
 
                cfg->jit_info->gc_info = emap;
+
+               cfg->gc_map = (guint8*)emap;
+               cfg->gc_map_size = alloc_size;
        }
 
        stats.all_slots += nslots;
@@ -2212,6 +2288,25 @@ mini_gc_create_gc_map (MonoCompile *cfg)
        create_map (cfg);
 }
 
+static void
+parse_debug_options (void)
+{
+       char **opts, **ptr;
+       char *env;
+
+       env = getenv ("MONO_GCMAP_DEBUG");
+       if (!env)
+               return;
+
+       opts = g_strsplit (env, ",", -1);
+       for (ptr = opts; ptr && *ptr; ptr ++) {
+               /* No options yet */
+               fprintf (stderr, "Invalid format for the MONO_GCMAP_DEBUG env variable: '%s'\n", env);
+               exit (1);
+       }
+       g_strfreev (opts);
+}
+
 void
 mini_gc_init (void)
 {
@@ -2225,6 +2320,10 @@ mini_gc_init (void)
        cb.thread_mark_func = thread_mark_func;
        mono_gc_set_gc_callbacks (&cb);
 
+       logfile = mono_gc_get_logfile ();
+
+       parse_debug_options ();
+
        mono_counters_register ("GC Maps size",
                                                        MONO_COUNTER_GC | MONO_COUNTER_INT, &stats.gc_maps_size);
        mono_counters_register ("GC Call Sites size",
@@ -2319,6 +2418,11 @@ mini_gc_init_cfg (MonoCompile *cfg)
  * - vtypes/refs used in EH regions are treated conservatively
  * - if the code is finished, less pinning will be done, causing problems because
  *   we promote all surviving objects to old-gen.
+ * - the unwind code can't handle a method stopped inside a finally region, it thinks the caller is
+ *   another method, but in reality it is either the exception handling code or the CALL_HANDLER opcode.
+ *   This manifests in "Unable to find ip offset x in callsite list" assertions.
+ * - the unwind code also can't handle frames which are in the epilog, since the unwind info is not
+ *   precise there.
  */
 
 /*