Add support for GC tracking of some spill slots.
authorZoltan Varga <vargaz@gmail.com>
Tue, 14 Sep 2010 22:19:24 +0000 (00:19 +0200)
committerZoltan Varga <vargaz@gmail.com>
Mon, 3 Jan 2011 14:42:18 +0000 (15:42 +0100)
mono/mini/cpu-amd64.md
mono/mini/mini-amd64.c
mono/mini/mini-codegen.c
mono/mini/mini-gc.c
mono/mini/mini-gc.h
mono/mini/mini-ops.h
mono/mini/mini.c
mono/mini/mini.h
mono/mini/regalloc.h

index 19bc314f074123e61637660422f1b560fbb1aa4d..15b3ad92e0dc4c18956312ac3e4d78aae7656e32 100644 (file)
@@ -702,3 +702,5 @@ liverange_start: len:0
 liverange_end: len:0
 gc_liveness_def: len:0
 gc_liveness_use: len:0
+gc_spill_slot_liveness_def: len:0
+
index e9dfa70f75d7ca90c7b7b51e1f1edf639888adf4..305ab2bbd479f79c89e2f52a053a76fca4082ae9 100644 (file)
@@ -5652,6 +5652,10 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                case OP_GC_LIVENESS_USE:
                        ins->backend.pc_offset = code - cfg->native_code;
                        break;
+               case OP_GC_SPILL_SLOT_LIVENESS_DEF:
+                       ins->backend.pc_offset = code - cfg->native_code;
+                       bb->spill_slot_defs = g_slist_prepend_mempool (cfg->mempool, bb->spill_slot_defs, ins);
+                       break;
                default:
                        g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
                        g_assert_not_reached ();
index 8c30c538e1f1c6b99defb8fd6c45998761b0ec69..3cda16d5f5618b66ca8cd9cba883300dfc22baeb 100644 (file)
@@ -70,24 +70,28 @@ static inline int translate_bank (MonoRegState *rs, int bank, int hreg) {
 static const int regbank_size [] = {
        MONO_MAX_IREGS,
        MONO_MAX_FREGS,
+       MONO_MAX_IREGS,
        MONO_MAX_XREGS
 };
 
 static const int regbank_load_ops [] = { 
        OP_LOADR_MEMBASE,
        OP_LOADR8_MEMBASE,
+       OP_LOADR_MEMBASE,
        OP_LOADX_MEMBASE
 };
 
 static const int regbank_store_ops [] = { 
        OP_STORER_MEMBASE_REG,
        OP_STORER8_MEMBASE_REG,
+       OP_STORER_MEMBASE_REG,
        OP_STOREX_MEMBASE
 };
 
 static const int regbank_move_ops [] = { 
        OP_MOVE,
        OP_FMOVE,
+       OP_MOVE,
        OP_XMOVE
 };
 
@@ -96,18 +100,21 @@ static const int regbank_move_ops [] = {
 static const regmask_t regbank_callee_saved_regs [] = {
        MONO_ARCH_CALLEE_SAVED_REGS,
        MONO_ARCH_CALLEE_SAVED_FREGS,
+       MONO_ARCH_CALLEE_SAVED_REGS,
        MONO_ARCH_CALLEE_SAVED_XREGS,
 };
 
 static const regmask_t regbank_callee_regs [] = {
        MONO_ARCH_CALLEE_REGS,
        MONO_ARCH_CALLEE_FREGS,
+       MONO_ARCH_CALLEE_REGS,
        MONO_ARCH_CALLEE_XREGS,
 };
 
 static const int regbank_spill_var_size[] = {
        sizeof (mgreg_t),
        sizeof (double),
+       sizeof (mgreg_t),
        16 /*FIXME make this a constant. Maybe MONO_ARCH_SIMD_VECTOR_SIZE? */
 };
 
@@ -134,12 +141,12 @@ mono_regstate_assign (MonoRegState *rs)
        memset (rs->isymbolic, 0, MONO_MAX_IREGS * sizeof (rs->isymbolic [0]));
        memset (rs->fsymbolic, 0, MONO_MAX_FREGS * sizeof (rs->fsymbolic [0]));
 
-       rs->symbolic [0] = rs->isymbolic;
-       rs->symbolic [1] = rs->fsymbolic;
+       rs->symbolic [MONO_REG_INT] = rs->isymbolic;
+       rs->symbolic [MONO_REG_DOUBLE] = rs->fsymbolic;
 
 #ifdef MONO_ARCH_NEED_SIMD_BANK
        memset (rs->xsymbolic, 0, MONO_MAX_XREGS * sizeof (rs->xsymbolic [0]));
-       rs->symbolic [2] = rs->xsymbolic;
+       rs->symbolic [MONO_REG_SIMD] = rs->xsymbolic;
 #endif
 }
 
@@ -266,7 +273,7 @@ resize_spill_info (MonoCompile *cfg, int bank)
 
        g_assert (bank < MONO_NUM_REGBANKS);
 
-       new_info = mono_mempool_alloc (cfg->mempool, sizeof (MonoSpillInfo) * new_len);
+       new_info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoSpillInfo) * new_len);
        if (orig_info)
                memcpy (new_info, orig_info, sizeof (MonoSpillInfo) * orig_len);
        for (i = orig_len; i < new_len; ++i)
@@ -682,6 +689,7 @@ spill_vreg (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **last, MonoInst *ins
        int i, sel, spill;
        int *symbolic;
        MonoRegState *rs = cfg->rs;
+       gboolean ref = vreg_is_ref (cfg, reg);
 
        symbolic = rs->symbolic [bank];
        sel = rs->vassign [reg];
@@ -702,7 +710,7 @@ spill_vreg (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **last, MonoInst *ins
        MONO_INST_NEW (cfg, load, regbank_load_ops [bank]);
        load->dreg = sel;
        load->inst_basereg = cfg->frame_reg;
-       load->inst_offset = mono_spillvar_offset (cfg, spill, bank);
+       load->inst_offset = mono_spillvar_offset (cfg, spill, ref ? MONO_REG_INT_REF : bank);
        insert_after_ins (bb, ins, last, load);
        DEBUG (printf ("SPILLED LOAD (%d at 0x%08lx(%%ebp)) R%d (freed %s)\n", spill, (long)load->inst_offset, i, mono_regname_full (sel, bank)));
        if (G_UNLIKELY (bank))
@@ -730,6 +738,7 @@ get_register_spilling (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **last, Mo
        int sregs [MONO_MAX_SRC_REGS];
        int *symbolic;
        MonoRegState *rs = cfg->rs;
+       gboolean is_ref;
 
        symbolic = rs->symbolic [bank];
 
@@ -789,11 +798,13 @@ get_register_spilling (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **last, Mo
                mono_regstate_free_int (rs, sel);
        }
 
+       is_ref = vreg_is_ref (cfg, i);
+
        /* we need to create a spill var and insert a load to sel after the current instruction */
        MONO_INST_NEW (cfg, load, regbank_load_ops [bank]);
        load->dreg = sel;
        load->inst_basereg = cfg->frame_reg;
-       load->inst_offset = mono_spillvar_offset (cfg, spill, bank);
+       load->inst_offset = mono_spillvar_offset (cfg, spill, is_ref ? MONO_REG_INT_REF : bank);
        insert_after_ins (bb, ins, last, load);
        DEBUG (printf ("\tSPILLED LOAD (%d at 0x%08lx(%%ebp)) R%d (freed %s)\n", spill, (long)load->inst_offset, i, mono_regname_full (sel, bank)));
        if (G_UNLIKELY (bank))
@@ -846,20 +857,33 @@ create_copy_ins (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **last, int dest
        return copy;
 }
 
-static MonoInst*
-create_spilled_store (MonoCompile *cfg, MonoBasicBlock *bb, int spill, int reg, int prev_reg, MonoInst **last, MonoInst *ins, int bank)
+static void
+create_spilled_store (MonoCompile *cfg, MonoBasicBlock *bb, int spill, int reg, int prev_reg, MonoInst **last, MonoInst *ins, MonoInst *insert_before, int bank)
 {
-       MonoInst *store;
+       MonoInst *store, *def;
+       gboolean is_ref = vreg_is_ref (cfg, prev_reg);
+
        MONO_INST_NEW (cfg, store, regbank_store_ops [bank]);
        store->sreg1 = reg;
        store->inst_destbasereg = cfg->frame_reg;
-       store->inst_offset = mono_spillvar_offset (cfg, spill, bank);
+       store->inst_offset = mono_spillvar_offset (cfg, spill, is_ref ? MONO_REG_INT_REF : bank);
        if (ins) {
                mono_bblock_insert_after_ins (bb, ins, store);
                *last = store;
+       } else if (insert_before) {
+               insert_before_ins (bb, insert_before, store);
+       } else {
+               g_assert_not_reached ();
        }
        DEBUG (printf ("\tSPILLED STORE (%d at 0x%08lx(%%ebp)) R%d (from %s)\n", spill, (long)store->inst_offset, prev_reg, mono_regname_full (reg, bank)));
-       return store;
+
+       if (is_ref && cfg->compute_gc_maps) {
+               g_assert (prev_reg != -1);
+               MONO_INST_NEW (cfg, def, OP_GC_SPILL_SLOT_LIVENESS_DEF);
+               def->inst_c0 = spill;
+               mono_bblock_insert_after_ins (bb, store, def);
+               *last = def;
+       }
 }
 
 /* flags used in reginfo->flags */
@@ -1423,13 +1447,11 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
 
                                if (need_assign) {
                                        if (rs->vassign [sreg] < -1) {
-                                               MonoInst *store;
                                                int spill;
 
                                                /* Need to emit a spill store */
                                                spill = - rs->vassign [sreg] - 1;
-                                               store = create_spilled_store (cfg, bb, spill, dest_sreg, sreg, tmp, NULL, bank);
-                                               insert_before_ins (bb, ins, store);
+                                               create_spilled_store (cfg, bb, spill, dest_sreg, sreg, tmp, NULL, ins, bank);
                                        }
                                        /* force-set sreg2 */
                                        assign_reg (cfg, rs, sregs [j], dest_sreg, 0);
@@ -1519,7 +1541,7 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
                                val = alloc_reg (cfg, bb, tmp, ins, dreg_mask, ins->dreg, &reginfo [ins->dreg], bank);
                                assign_reg (cfg, rs, ins->dreg, val, bank);
                                if (spill)
-                                       create_spilled_store (cfg, bb, spill, val, prev_dreg, tmp, ins, bank);
+                                       create_spilled_store (cfg, bb, spill, val, prev_dreg, tmp, ins, NULL, bank);
                        }
 
                        DEBUG (printf ("\tassigned dreg %s to dest R%d\n", mono_regname_full (val, bank), ins->dreg));
@@ -1549,7 +1571,7 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
                                if (val < 0)
                                        val = get_register_spilling (cfg, bb, tmp, ins, mask, reg2, bank);
                                if (spill)
-                                       create_spilled_store (cfg, bb, spill, val, reg2, tmp, ins, bank);
+                                       create_spilled_store (cfg, bb, spill, val, reg2, tmp, ins, NULL, bank);
                        }
                        else {
                                if (! (mask & (regmask (val)))) {
@@ -1850,12 +1872,11 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
                                DEBUG (printf ("\tassigned sreg1 %s to R%d\n", mono_regname_full (val, bank), sregs [0]));
 
                                if (spill) {
-                                       MonoInst *store = create_spilled_store (cfg, bb, spill, val, prev_sregs [0], tmp, NULL, bank);
                                        /*
                                         * Need to insert before the instruction since it can
                                         * overwrite sreg1.
                                         */
-                                       insert_before_ins (bb, ins, store);
+                                       create_spilled_store (cfg, bb, spill, val, prev_sregs [0], tmp, NULL, ins, bank);
                                }
                        }
                        else if ((dest_sregs [0] != -1) && (dest_sregs [0] != val)) {
@@ -2017,12 +2038,11 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
                                        assign_reg (cfg, rs, sregs [j], val, bank);
                                        DEBUG (printf ("\tassigned sreg%d %s to R%d\n", j + 1, mono_regname_full (val, bank), sregs [j]));
                                        if (spill) {
-                                               MonoInst *store = create_spilled_store (cfg, bb, spill, val, prev_sregs [j], tmp, NULL, bank);
                                                /*
                                                 * Need to insert before the instruction since it can
                                                 * overwrite sreg2.
                                                 */
-                                               insert_before_ins (bb, ins, store);
+                                               create_spilled_store (cfg, bb, spill, val, sregs [j], tmp, NULL, ins, bank);
                                        }
                                }
                                sregs [j] = val;
index fe191b4aa8c5f49899694470c6d3ebc0e0088ac8..dcd35e6f4198b6bc66ef4540e0c88cbf70b2cbdb 100644 (file)
@@ -30,6 +30,8 @@ typedef struct {
         * means cfa+0, 1 means cfa-4/8, etc.
         */
        GSList *stack_slots_from_cfa;
+       /* Same for stack slots relative to the frame pointer */
+       GSList *stack_slots_from_fp;
 
        /* Number of slots in the map */
        int nslots;
@@ -41,6 +43,8 @@ typedef struct {
        gboolean *starts_pinned;
        /* Min and Max offsets of the stack frame relative to fp */
        int min_offset, max_offset;
+       /* Same for the locals area */
+       int locals_min_offset, locals_max_offset;
 } MonoCompileGC;
 
 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
@@ -386,11 +390,46 @@ mini_gc_init_gc_map (MonoCompile *cfg)
        if (COMPILE_LLVM (cfg))
                return;
 
+#if 1
+       /* Debugging support */
+       {
+               static int precise_count;
+
+               precise_count ++;
+               if (getenv ("MONO_GCMAP_COUNT")) {
+                       if (precise_count == atoi (getenv ("MONO_GCMAP_COUNT")))
+                               printf ("LAST: %s\n", mono_method_full_name (cfg->method, TRUE));
+                       if (precise_count > atoi (getenv ("MONO_GCMAP_COUNT")))
+                               return;
+               }
+       }
+#endif
+
        cfg->compute_gc_maps = TRUE;
 
        cfg->gc_info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoCompileGC));
 }
 
+/*
+ * mini_gc_set_slot_type_from_fp:
+ *
+ *   Set the GC slot type of the stack slot identified by SLOT_OFFSET, which should be
+ * relative to the frame pointer. By default, all stack slots are type PIN, so there is no
+ * need to call this function for those slots.
+ */
+void
+mini_gc_set_slot_type_from_fp (MonoCompile *cfg, int slot_offset, StackSlotType type)
+{
+       MonoCompileGC *gcfg = (MonoCompileGC*)cfg->gc_info;
+
+       if (!cfg->compute_gc_maps)
+               return;
+
+       g_assert (slot_offset % sizeof (mgreg_t) == 0);
+
+       gcfg->stack_slots_from_fp = g_slist_prepend_mempool (cfg->mempool, gcfg->stack_slots_from_fp, GINT_TO_POINTER (((slot_offset) << 16) | type));
+}
+
 /*
  * mini_gc_set_slot_type_from_cfa:
  *
@@ -399,7 +438,6 @@ mini_gc_init_gc_map (MonoCompile *cfg)
  * If type is STACK_REF, the slot is assumed to be live from the end of the prolog until
  * the end of the method. By default, all stack slots are type PIN, so there is no need to
  * call this function for those slots.
- * FIXME: Add a variant for fp relative offsets.
  */
 void
 mini_gc_set_slot_type_from_cfa (MonoCompile *cfg, int slot_offset, StackSlotType type)
@@ -419,10 +457,49 @@ mini_gc_set_slot_type_from_cfa (MonoCompile *cfg, int slot_offset, StackSlotType
 static inline void
 set_slot (MonoCompileGC *gcfg, int pos, StackSlotType val)
 {
-       g_assert (pos < gcfg->nslots);
+       g_assert (pos >= 0 && pos < gcfg->nslots);
        gcfg->slots [pos] = val;
 }
 
+static inline int
+fp_offset_to_slot (MonoCompile *cfg, int offset)
+{
+       MonoCompileGC *gcfg = cfg->gc_info;
+
+       return (offset - gcfg->min_offset) / sizeof (mgreg_t);
+}
+
+static void
+process_spill_slots (MonoCompile *cfg)
+{
+       MonoCompileGC *gcfg = cfg->gc_info;
+       MonoBasicBlock *bb;
+       GSList *l;
+
+       for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
+               /*
+                * Extend the live interval for the GC tracked spill slots
+                * defined in this bblock.
+                */
+               for (l = bb->spill_slot_defs; l; l = l->next) {
+                       MonoInst *def = l->data;
+                       int spill_slot = def->inst_c0;
+                       int offset = cfg->spill_info [MONO_REG_INT_REF][spill_slot].offset;
+                       int slot = fp_offset_to_slot (cfg, offset);
+                       MonoLiveInterval *interval;
+
+                       set_slot (gcfg, slot, SLOT_REF);
+
+                       interval = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoLiveInterval));
+                       mono_linterval_add_range (cfg, interval, def->backend.pc_offset, bb->native_offset + bb->native_length);
+                       gcfg->live_intervals [slot] = g_slist_prepend_mempool (cfg->mempool, gcfg->live_intervals [slot], interval);
+
+                       if (cfg->verbose_level > 1)
+                               printf ("\tref spill slot at fp+0x%x (slot = %d)\n", offset, slot);
+               }
+       }
+}
+
 /*
  * process_other_slots:
  *
@@ -433,7 +510,8 @@ process_other_slots (MonoCompile *cfg)
 {
        MonoCompileGC *gcfg = cfg->gc_info;
        GSList *l;
-       
+
+       /* Relative to the CFA */
        for (l = gcfg->stack_slots_from_cfa; l; l = l->next) {
                guint data = GPOINTER_TO_UINT (l->data);
                int slot = data >> 16;
@@ -455,18 +533,45 @@ process_other_slots (MonoCompile *cfg)
                                printf ("\tnoref at fp+0x%x (slot = %d) (cfa - 0x%x)\n", (int)(fp_slot * sizeof (mgreg_t)), fp_slot, (int)(slot * sizeof (mgreg_t)));
                }
        }
+
+       /* Relative to the FP */
+       for (l = gcfg->stack_slots_from_fp; l; l = l->next) {
+               guint data = GPOINTER_TO_INT (l->data);
+               int offset = data >> 16;
+               StackSlotType type = data & 0xff;
+               int slot;
+               
+               slot = fp_offset_to_slot (cfg, offset);
+
+               set_slot (gcfg, slot, type);
+
+               /* Liveness for these slots is handled by process_spill_slots () */
+
+               if (cfg->verbose_level > 1) {
+                       if (type == SLOT_REF)
+                               printf ("\tref at fp+0x%x (slot = %d)\n", offset, slot);
+               }
+       }
 }
 
 static void
 process_locals (MonoCompile *cfg)
 {
-       int i;
+       int i, locals_min_slot, locals_max_slot;
        MonoBasicBlock *bb;
        MonoInst *tmp;
        int *pc_offsets;
        MonoCompileGC *gcfg = cfg->gc_info;
        GSList **live_intervals = gcfg->live_intervals;
        gboolean *starts_pinned = gcfg->starts_pinned;
+       int locals_min_offset = gcfg->locals_min_offset;
+       int locals_max_offset = gcfg->locals_max_offset;
+
+       /* Slots for locals are NOREF by default */
+       locals_min_slot = (locals_min_offset - gcfg->min_offset) / sizeof (gpointer);
+       locals_max_slot = (locals_max_offset - gcfg->min_offset) / sizeof (gpointer);
+       for (i = locals_min_slot; i < locals_max_slot; ++i)
+               set_slot (gcfg, i, SLOT_NOREF);
 
        /*
         * Compute the offset where variables are initialized in the first bblock, if any.
@@ -499,7 +604,7 @@ process_locals (MonoCompile *cfg)
                if (ins->inst_offset % sizeof (gpointer) != 0)
                        continue;
 
-               pos = (ins->inst_offset - gcfg->min_offset) / sizeof (gpointer);
+               pos = fp_offset_to_slot (cfg, ins->inst_offset);
 
                if (MONO_TYPE_ISSTRUCT (t)) {
                        int numbits = 0, j;
@@ -722,13 +827,65 @@ process_arguments (MonoCompile *cfg)
        }
 }
 
+static void
+compute_frame_size (MonoCompile *cfg)
+{
+       int i, locals_min_offset, locals_max_offset, cfa_min_offset, cfa_max_offset;
+       int min_offset, max_offset;
+       MonoCompileGC *gcfg = cfg->gc_info;
+       MonoMethodSignature *sig = mono_method_signature (cfg->method);
+
+       /* Compute min/max offsets from the fp */
+
+       /* Locals */
+#ifdef TARGET_AMD64
+       locals_min_offset = ALIGN_TO (cfg->locals_min_stack_offset, sizeof (gpointer));
+       locals_max_offset = cfg->locals_max_stack_offset;
+#else
+       /* min/max stack offset needs to be computed in mono_arch_allocate_vars () */
+       NOT_IMPLEMENTED;
+#endif
+
+       locals_min_offset = ALIGN_TO (locals_min_offset, sizeof (gpointer));
+       locals_max_offset = ALIGN_TO (locals_max_offset, sizeof (gpointer));
+
+       min_offset = locals_min_offset;
+       max_offset = locals_max_offset;
+
+       /* Arguments */
+       for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
+               MonoInst *ins = cfg->args [i];
+
+               if (ins->opcode == OP_REGOFFSET)
+                       min_offset = MIN (min_offset, ins->inst_offset);
+       }
+
+       /* Cfa slots */
+       g_assert (cfg->frame_reg == cfg->cfa_reg);
+       g_assert (cfg->cfa_offset > 0);
+       cfa_min_offset = 0;
+       cfa_max_offset = cfg->cfa_offset;
+
+       min_offset = MIN (min_offset, cfa_min_offset);
+       max_offset = MAX (max_offset, cfa_max_offset);
+
+       /* Spill slots */
+       if (!(cfg->flags & MONO_CFG_HAS_SPILLUP)) {
+               int stack_offset = ALIGN_TO (cfg->stack_offset, sizeof (mgreg_t));
+               min_offset = MIN (min_offset, (-stack_offset));
+       }
+
+       gcfg->min_offset = min_offset;
+       gcfg->max_offset = max_offset;
+       gcfg->locals_min_offset = locals_min_offset;
+       gcfg->locals_max_offset = locals_max_offset;
+}
+
 void
 mini_gc_create_gc_map (MonoCompile *cfg)
 {
        GCMap *map;
-       int i, locals_min_offset, locals_max_offset, cfa_min_offset, cfa_max_offset;
-       int min_offset, max_offset, locals_min_slot, locals_max_slot;
-       int nslots, alloc_size;
+       int i, nslots, alloc_size;
        int ntypes [16];
        StackSlotType *slots = NULL;
        GSList **live_intervals;
@@ -736,7 +893,9 @@ mini_gc_create_gc_map (MonoCompile *cfg)
        gboolean *starts_pinned;
        gboolean has_ref_slots, has_pin_slots;
        MonoCompileGC *gcfg = cfg->gc_info;
-       MonoMethodSignature *sig = mono_method_signature (cfg->method);
+
+       if (!cfg->compute_gc_maps)
+               return;
 
        /*
         * Since we currently don't use GC safe points, we need to create GC maps which
@@ -770,40 +929,8 @@ mini_gc_create_gc_map (MonoCompile *cfg)
                return;
 
        mono_analyze_liveness_gc (cfg);
-
-       /* Compute min/max offsets from the fp */
-
-       /* Locals */
-#ifdef TARGET_AMD64
-       locals_min_offset = ALIGN_TO (cfg->locals_min_stack_offset, sizeof (gpointer));
-       locals_max_offset = cfg->locals_max_stack_offset;
-#else
-       /* min/max stack offset needs to be computed in mono_arch_allocate_vars () */
-       NOT_IMPLEMENTED;
-#endif
-
-       locals_min_offset = ALIGN_TO (locals_min_offset, sizeof (gpointer));
-       locals_max_offset = ALIGN_TO (locals_max_offset, sizeof (gpointer));
-
-       min_offset = locals_min_offset;
-       max_offset = locals_max_offset;
-
-       /* Arguments */
-       for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
-               MonoInst *ins = cfg->args [i];
-
-               if (ins->opcode == OP_REGOFFSET)
-                       min_offset = MIN (min_offset, ins->inst_offset);
-       }
-
-       /* Cfa slots */
-       g_assert (cfg->frame_reg == cfg->cfa_reg);
-       g_assert (cfg->cfa_offset > 0);
-       cfa_min_offset = 0;
-       cfa_max_offset = cfg->cfa_offset;
-
-       min_offset = MIN (min_offset, cfa_min_offset);
-       max_offset = MAX (max_offset, cfa_max_offset);
+       
+       compute_frame_size (cfg);
 
        /*
         * The stack frame looks like this:
@@ -818,9 +945,9 @@ mini_gc_create_gc_map (MonoCompile *cfg)
         */
 
        if (cfg->verbose_level > 1)
-               printf ("GC Map for %s: 0x%x-0x%x\n", mono_method_full_name (cfg->method, TRUE), min_offset, max_offset);
+               printf ("GC Map for %s: 0x%x-0x%x\n", mono_method_full_name (cfg->method, TRUE), gcfg->min_offset, gcfg->max_offset);
 
-       nslots = (max_offset - min_offset) / sizeof (gpointer);
+       nslots = (gcfg->max_offset - gcfg->min_offset) / sizeof (gpointer);
        /* slot [i] == type of slot at fp - <min_offset> + i*4/8 */
        slots = g_new0 (StackSlotType, nslots);
        live_intervals = g_new0 (GSList*, nslots);
@@ -830,40 +957,16 @@ mini_gc_create_gc_map (MonoCompile *cfg)
        gcfg->nslots = nslots;
        gcfg->live_intervals = live_intervals;
        gcfg->starts_pinned = starts_pinned;
-       gcfg->min_offset = min_offset;
-       gcfg->max_offset = max_offset;
 
        /* All slots start out as PIN */
        for (i = 0; i < nslots; ++i)
-               slots [i] = SLOT_PIN;
-
-       /* Slots for locals are NOREF by default */
-       locals_min_slot = (locals_min_offset - min_offset) / sizeof (gpointer);
-       locals_max_slot = (locals_max_offset - min_offset) / sizeof (gpointer);
-       for (i = locals_min_slot; i < locals_max_slot; ++i)
-               slots [i] = SLOT_NOREF;
+               set_slot (gcfg, i, SLOT_PIN);
 
+       process_spill_slots (cfg);
        process_other_slots (cfg);
        process_locals (cfg);
        process_arguments (cfg);
 
-#if 1
-       /* Debugging support */
-       {
-               static int precise_count;
-
-               precise_count ++;
-               if (getenv ("MONO_GCMAP_COUNT")) {
-                       if (precise_count == atoi (getenv ("MONO_GCMAP_COUNT")))
-                               printf ("LAST: %s\n", mono_method_full_name (cfg->method, TRUE));
-                       if (precise_count > atoi (getenv ("MONO_GCMAP_COUNT"))) {
-                               for (i = 0; i < nslots; ++i)
-                                       slots [i] = SLOT_PIN;
-                       }
-               }
-       }
-#endif
-
        /* Create the GC Map */
 
        has_ref_slots = FALSE;
@@ -887,7 +990,7 @@ mini_gc_create_gc_map (MonoCompile *cfg)
        gc_maps_size += alloc_size;
 
        map->frame_reg = cfg->frame_reg;
-       map->frame_offset = min_offset;
+       map->frame_offset = gcfg->min_offset;
        map->nslots = nslots;
        map->bitmap_width = bitmap_width;
        map->has_ref_slots = has_ref_slots;
index 83e759879136acde2b0112d5d5d8d3dd5756dc06..727840d74bc65950a1879f2ff8d037a8895eb352 100644 (file)
@@ -24,6 +24,8 @@ void mini_gc_init_cfg (MonoCompile *cfg) MONO_INTERNAL;
 
 void mini_gc_create_gc_map (MonoCompile *cfg) MONO_INTERNAL;
 
+void mini_gc_set_slot_type_from_fp (MonoCompile *cfg, int slot_offset, StackSlotType type) MONO_INTERNAL;
+
 void mini_gc_set_slot_type_from_cfa (MonoCompile *cfg, int slot_offset, StackSlotType type) MONO_INTERNAL;
 
 #endif
index 9b66fdab5f71e26fb9cecb7b934546c8a96101e4..65575a47375fced8de603f80730f6525e8967bae 100644 (file)
@@ -878,6 +878,12 @@ MINI_OP(OP_LIVERANGE_END, "liverange_end", NONE, NONE, NONE)
 MINI_OP(OP_GC_LIVENESS_DEF, "gc_liveness_def", NONE, NONE, NONE)
 MINI_OP(OP_GC_LIVENESS_USE, "gc_liveness_use", NONE, NONE, NONE)
 
+/*
+ * This marks the location inside a basic block where a GC tracked spill slot has been
+ * defined. The spill slot is assumed to be alive until the end of the bblock.
+ */
+MINI_OP(OP_GC_SPILL_SLOT_LIVENESS_DEF, "gc_spill_slot_liveness_def", NONE, NONE, NONE)
+
 /* Arch specific opcodes */
 #if defined(TARGET_X86) || defined(TARGET_AMD64)
 MINI_OP(OP_X86_TEST_NULL,          "x86_test_null", NONE, IREG, NONE)
index 5ea6e4353588bb3e27de58dfb4b849082ff95113..556e1cd8a9bb4b199e43036bd396b1ed21bfc967 100644 (file)
@@ -1040,8 +1040,10 @@ mono_compile_create_var_for_vreg (MonoCompile *cfg, MonoType *type, int opcode,
        inst->dreg = vreg;
 
        if (cfg->compute_gc_maps) {
-               if ((MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->klass->has_references) || MONO_TYPE_IS_REFERENCE (inst->inst_vtype))
+               if ((MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->klass->has_references) || MONO_TYPE_IS_REFERENCE (inst->inst_vtype)) {
                        inst->flags |= MONO_INST_GC_TRACK;
+                       mono_mark_vreg_as_ref (cfg, vreg);
+               }
        }
        
        cfg->varinfo [num] = inst;
index 30925c7def735caca2006797bbb3c4e9254ca30a..17cbb017daa198277bd9127aa6ecc6400761c6a6 100644 (file)
@@ -554,6 +554,8 @@ struct MonoBasicBlock {
        GSList *seq_points;
        MonoInst *last_seq_point;
 
+       GSList *spill_slot_defs;
+
        /*
         * The region encodes whether the basic block is inside
         * a finally, catch, filter or none of these.
index 898b1e0a75f0a88f2746c9d818b2096ff295f2ff..6c4959bef099785749dda460a86656afbe1bd64b 100644 (file)
@@ -4,14 +4,16 @@ typedef size_t regmask_t;
 enum {
        MONO_REG_INT,
        MONO_REG_DOUBLE,
+       /* This is used only for allocating spill slots with GC tracking */
+       MONO_REG_INT_REF,
        MONO_REG_SIMD
 };
 
  
 #ifdef MONO_ARCH_NEED_SIMD_BANK
-#define MONO_NUM_REGBANKS 3
+#define MONO_NUM_REGBANKS 4
 #else
-#define MONO_NUM_REGBANKS 2
+#define MONO_NUM_REGBANKS 3
 #endif
 
 typedef struct {