Disable GC maps for methods with causes for now.
[mono.git] / mono / mini / mini-gc.c
1 /*
2  * mini-gc.c: GC interface for the mono JIT
3  *
4  * Author:
5  *   Zoltan Varga (vargaz@gmail.com)
6  *
7  * Copyright 2009 Novell, Inc (http://www.novell.com)
8  */
9
10 #include "config.h"
11 #include "mini-gc.h"
12 #include <mono/metadata/gc-internal.h>
13
14 /*
15  * The code below does not work yet, and probably needs to be thrown out if we move
16  * to GC safe points.
17  */
18
19 //#if 0
20 #ifdef HAVE_SGEN_GC
21
22 #include <mono/metadata/gc-internal.h>
23 #include <mono/utils/mono-counters.h>
24
25 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
26
27 #if 0
28 #define DEBUG(s) do { s; } while (0)
29 #else
30 #define DEBUG(s)
31 #endif
32
33 #if 1
34 #define DEBUG_GC_MAP(s) do { s; fflush (stdout); } while (0)
35 #else
36 #define DEBUG_GC_MAP(s)
37 #endif
38
39 #define GC_BITS_PER_WORD (sizeof (gsize) * 8)
40
41 /*
42  * Per-thread data kept by this module. This is stored in the GC and passed to us as
43  * parameters, instead of being stored in a TLS variable, since during a collection,
44  * only the collection thread is active.
45  */
46 typedef struct {
47         MonoLMF *lmf;
48         MonoContext ctx;
49         gboolean has_context;
50         MonoJitTlsData *jit_tls;
51 } TlsData;
52
53 typedef enum {
54         /* Stack slot doesn't contain a reference */
55         SLOT_NOREF = 0,
56         /* Stack slot contains a reference */
57         SLOT_REF = 1,
58         /* No info, slot needs to be scanned conservatively */
59         SLOT_PIN = 2
60 } StackSlotType;
61
62 /* 
63  * Contains information needed to mark a stack frame.
64  * FIXME: Optimize the memory usage.
65  */
66 typedef struct {
67         /* The frame pointer register */
68         int frame_reg;
69         /* The offset of the local variable area in the stack frame relative to the frame pointer */
70         int locals_offset;
71         /* The size of the locals area. Can't use nslots as it includes padding */
72         int locals_size;
73         /* The number of stack slots */
74         int nslots;
75         /* The width of the liveness bitmap in bytes */
76         int bitmap_width;
77         /* 
78          * The gc map itself.
79          */
80         StackSlotType *slots;
81         /* 
82          * A bitmap whose width is equal to the number of SLOT_REF values in gc_refs, and whose
83          * height is equal to the number of possible PC offsets.
84          * This needs to be compressed later.
85          */
86         guint8 bitmap [MONO_ZERO_LEN_ARRAY];
87 } GCMap;
88
89 /* Statistics */
90 static guint32 gc_maps_size;
91
92 static gpointer
93 thread_attach_func (void)
94 {
95         return g_new0 (TlsData, 1);
96 }
97
98 static void
99 thread_suspend_func (gpointer user_data, void *sigctx)
100 {
101         TlsData *tls = user_data;
102
103         if (!tls)
104                 /* Happens during startup */
105                 return;
106
107         tls->lmf = mono_get_lmf ();
108         if (sigctx) {
109                 mono_arch_sigctx_to_monoctx (sigctx, &tls->ctx);
110                 tls->has_context = TRUE;
111         } else {
112                 tls->has_context = FALSE;
113         }
114         tls->jit_tls = TlsGetValue (mono_jit_tls_id);
115 }
116
117 static int precise_frame_count [2], precise_frame_limit = -1;
118 static gboolean precise_frame_limit_inited;
119
120 static int scanned_stacks_stat;
121 static int scanned_stat, scanned_precisely_stat, scanned_conservatively_stat;
122
123 #define DEAD_REF ((gpointer)(gssize)0x2a2a2a2a2a2a2a2aULL)
124
125 static void
126 thread_mark_func (gpointer user_data, guint8 *stack_start, guint8 *stack_end, gboolean precise)
127 {
128         TlsData *tls = user_data;
129         MonoJitInfo *ji, res;
130         MonoContext ctx, new_ctx;
131         MonoLMF *lmf;
132         guint8 *stack_limit;
133         gboolean last = TRUE, managed;
134         GCMap *map;
135         guint8* fp, *locals_start, *locals_end;
136         int i, pc_offset;
137         int scanned = 0, scanned_precisely, scanned_conservatively;
138
139         /* tls == NULL can happen during startup */
140         if (mono_thread_internal_current () == NULL || !tls) {
141                 if (!precise) {
142                         mono_gc_conservatively_scan_area (stack_start, stack_end);
143                         scanned_stacks_stat += stack_end - stack_start;
144                 }
145                 return;
146         }
147
148         lmf = tls->lmf;
149
150         /* Number of bytes scanned based on GC map data */
151         scanned = 0;
152         /* Number of bytes scanned precisely based on GC map data */
153         scanned_precisely = 0;
154         /* Number of bytes scanned conservatively based on GC map data */
155         scanned_conservatively = 0;
156
157         /* FIXME: sgen-gc.c calls this multiple times for each major collection from pin_from_roots */
158
159         /* FIXME: Use real gc descriptors instead of bitmaps */
160
161         /* This is one past the last address which we have scanned */
162         stack_limit = stack_start;
163
164         DEBUG (printf ("*** %s stack marking %p-%p ***\n", precise ? "Precise" : "Conservative", stack_start, stack_end));
165
166         if (!tls->has_context)
167                 memset (&new_ctx, 0, sizeof (ctx));
168         else
169                 memcpy (&new_ctx, &tls->ctx, sizeof (MonoContext));
170
171         while (TRUE) {
172                 memcpy (&ctx, &new_ctx, sizeof (ctx));
173
174                 g_assert ((guint64)stack_limit % sizeof (gpointer) == 0);
175
176                 // FIXME: This doesn't work with appdomain transitions
177                 ji = mono_find_jit_info (mono_domain_get (), tls->jit_tls, &res, NULL,
178                                                                  &ctx, &new_ctx, NULL, &lmf, NULL, &managed);
179                 if (ji == (gpointer)-1)
180                         break;
181
182                 /* The last frame can be in any state so mark conservatively */
183                 if (last) {
184                         last = FALSE;
185                         continue;
186                 }
187
188                 /* These frames are returned by mono_find_jit_info () two times */
189                 if (!managed)
190                         continue;
191
192                 /* Scan the frame of this method */
193
194                 /*
195                  * A frame contains the following:
196                  * - saved registers
197                  * - saved args
198                  * - locals
199                  * - spill area
200                  * - localloc-ed memory
201                  * Currently, only the locals are scanned precisely.
202                  */
203
204                 map = ji->gc_info;
205
206                 if (!map) {
207                         DEBUG (char *fname = mono_method_full_name (ji->method, TRUE); printf ("Mark(%d): No GC map for %s\n", precise, fname); g_free (fname));
208                         continue;
209                 }
210
211                 /*
212                  * Debugging aid to control the number of frames scanned precisely
213                  */
214                 if (!precise_frame_limit_inited) {
215                         if (getenv ("MONO_PRECISE_COUNT"))
216                                 precise_frame_limit = atoi (getenv ("MONO_PRECISE_COUNT"));
217                         precise_frame_limit_inited = TRUE;
218                 }
219                                 
220                 if (precise_frame_limit != -1) {
221                         if (precise_frame_count [precise] == precise_frame_limit)
222                                 printf ("LAST PRECISE FRAME: %s\n", mono_method_full_name (ji->method, TRUE));
223                         if (precise_frame_count [precise] > precise_frame_limit)
224                                 continue;
225                 }
226                 precise_frame_count [precise] ++;
227
228 #ifdef __x86_64__
229                 if (map->frame_reg == AMD64_RSP)
230                         fp = (guint8*)ctx.rsp;
231                 else if (map->frame_reg == AMD64_RBP)
232                         fp = (guint8*)ctx.rbp;
233                 else
234                         g_assert_not_reached ();
235 #else
236                 fp = NULL;
237                 g_assert_not_reached ();
238 #endif
239
240                 locals_start = fp + map->locals_offset;
241                 locals_end = locals_start + map->locals_size;
242
243                 pc_offset = (guint8*)MONO_CONTEXT_GET_IP (&ctx) - (guint8*)ji->code_start;
244                 g_assert (pc_offset >= 0);
245
246                 DEBUG (char *fname = mono_method_full_name (ji->method, TRUE); printf ("Mark(%d): %s+0x%x (%p) limit=%p fp=%p locals=%p-%p (%d)\n", precise, fname, pc_offset, (gpointer)MONO_CONTEXT_GET_IP (&ctx), stack_limit, fp, locals_start, locals_end, (int)(locals_end - locals_start)); g_free (fname));
247
248                 /* 
249                  * FIXME: Add a function to mark using a bitmap, to avoid doing a 
250                  * call for each object.
251                  */
252
253                 scanned += locals_end - locals_start;
254
255                 /* Pinning needs to be done first, then the precise scan later */
256
257                 if (!precise) {
258                         g_assert (locals_start >= stack_limit);
259
260                         if (locals_start > stack_limit) {
261                                 /* This scans the previously skipped frames as well */
262                                 DEBUG (printf ("\tscan area %p-%p.\n", stack_limit, locals_start));
263                                 mono_gc_conservatively_scan_area (stack_limit, locals_start);
264                         }
265
266                         if (map->slots) {
267                                 guint8 *p;
268
269                                 p = locals_start;
270                                 for (i = 0; i < map->nslots; ++i) {
271                                         if (map->slots [i] == SLOT_PIN) {
272                                                 DEBUG (printf ("\tscan slot %s0x%x(fp)=%p.\n", (guint8*)p > (guint8*)fp ? "" : "-", ABS ((int)((gssize)p - (gssize)fp)), p));
273                                                 mono_gc_conservatively_scan_area (p, p + sizeof (gpointer));
274                                                 scanned_conservatively += sizeof (gpointer);
275                                         }
276                                         p += sizeof (gpointer);
277                                 }
278                         }
279
280                         stack_limit = locals_end;
281                 } else {
282                         if (map->slots) {
283                                 int loffset = 0;
284                                 guint8 *bitmap = &map->bitmap [(map->bitmap_width * pc_offset)];
285                                 gboolean live;
286
287                                 for (i = 0; i < map->nslots; ++i) {
288                                         if (map->slots [i] == SLOT_REF) {
289                                                 MonoObject **ptr = (MonoObject**)(locals_start + (i * sizeof (gpointer)));
290                                                 MonoObject *obj = *ptr;
291
292                                                 live = bitmap [loffset / 8] & (1 << (loffset % 8));
293
294                                                 if (live) {
295                                                         if (obj) {
296                                                                 DEBUG (printf ("\tref %s0x%x(fp)=%p: %p ->", (guint8*)ptr >= (guint8*)fp ? "" : "-", ABS ((int)((gssize)ptr - (gssize)fp)), ptr, obj));
297                                                                 *ptr = mono_gc_scan_object (obj);
298                                                                 DEBUG (printf (" %p.\n", *ptr));
299                                                         } else {
300                                                                 DEBUG (printf ("\tref %s0x%x(fp)=%p: %p.\n", (guint8*)ptr >= (guint8*)fp ? "" : "-", ABS ((int)((gssize)ptr - (gssize)fp)), ptr, obj));
301                                                         }
302                                                 } else {
303                                                         DEBUG (printf ("\tref %s0x%x(fp)=%p: dead (%p)\n", (guint8*)ptr >= (guint8*)fp ? "" : "-", ABS ((int)((gssize)ptr - (gssize)fp)), ptr, obj));
304                                                         /*
305                                                          * Fail fast if the live range is incorrect, and
306                                                          * the JITted code tries to access this object
307                                                          */
308                                                         *ptr = DEAD_REF;
309                                                 }
310
311                                                 loffset ++;
312                                                 scanned_precisely += sizeof (gpointer);
313                                         } else if (map->slots [i] == SLOT_NOREF) {
314                                                 scanned_precisely += sizeof (gpointer);
315                                         }
316                                 }
317                         }
318                 }
319         }
320
321         if (stack_limit < stack_end && !precise) {
322                 DEBUG (printf ("\tscan area %p-%p.\n", stack_limit, stack_end));
323                 mono_gc_conservatively_scan_area (stack_limit, stack_end);
324         }
325
326         DEBUG (printf ("Marked %d bytes, p=%d,c=%d out of %d.\n", scanned, scanned_precisely, scanned_conservatively, (int)(stack_end - stack_start)));
327
328         if (precise) {
329                 scanned_precisely_stat += scanned_precisely;
330         } else {
331                 scanned_stacks_stat += stack_end - stack_start;
332                 scanned_stat += scanned;
333                 scanned_conservatively_stat += scanned_conservatively;
334         }
335
336         //mono_gc_conservatively_scan_area (stack_start, stack_end);
337 }
338
339 #define set_slot(slots, nslots, pos, val) do {  \
340                 g_assert ((pos) < (nslots));               \
341                 (slots) [(pos)] = (val);                           \
342         } while (0)
343
344 static void
345 mini_gc_init_gc_map (MonoCompile *cfg)
346 {
347         if (COMPILE_LLVM (cfg))
348                 return;
349
350         cfg->compute_gc_maps = TRUE;
351 }
352
353 void
354 mini_gc_create_gc_map (MonoCompile *cfg)
355 {
356         GCMap *map;
357         int i, nslots, alloc_size, loffset, min_offset, max_offset;
358         StackSlotType *slots = NULL;
359         gboolean norefs = FALSE;
360         GSList **live_intervals;
361         int bitmap_width, bitmap_size;
362
363         /*
364          * Since we currently don't use GC safe points, we need to create GC maps which
365          * are precise at every instruction within a method. The live ranges calculated by
366          * the liveness pass are not usable for this, since they contain abstract positions, not
367          * pc offsets. The live ranges calculated by mono_spill_global_vars () are not usable
368          * either, since they can't model holes. Instead of these, we implement our own
369          * liveness analysis which is precise, and works with PC offsets. It calculates live
370          * intervals, which are unions of live ranges.
371          * FIXME:
372          * - arguments (these are not scanned precisely currently).
373          * - it would simplify things if we extended live ranges to the end of basic blocks
374          * instead of computing them precisely.
375          * - maybe mark loads+stores as needing GC tracking, instead of using DEF/USE
376          * instructions ?
377          */
378
379         if (!(cfg->comp_done & MONO_COMP_LIVENESS))
380                 /* Without liveness info, the live ranges are not precise enough */
381                 return;
382
383         if (cfg->header->num_clauses)
384                 /*
385                  * The calls to the finally clauses don't show up in the cfg. See
386                  * test_0_liveness_8 ().
387                  */
388                 return;
389
390         mono_analyze_liveness_gc (cfg);
391
392 #ifdef TARGET_AMD64
393         min_offset = ALIGN_TO (cfg->locals_min_stack_offset, sizeof (gpointer));
394         max_offset = cfg->locals_max_stack_offset;
395 #else
396         /* min/max stack offset needs to be computed in mono_arch_allocate_vars () */
397         NOT_IMPLEMENTED;
398 #endif
399
400         for (i = cfg->locals_start; i < cfg->num_varinfo; i++) {
401                 MonoInst *ins = cfg->varinfo [i];
402                 MonoType *t = ins->inst_vtype;
403
404                 if ((MONO_TYPE_ISSTRUCT (t) && ins->klass->has_references))
405                         break;
406                 if (MONO_TYPE_ISSTRUCT (t))
407                         break;
408                 if (t->byref || t->type == MONO_TYPE_PTR)
409                         break;
410                 if (ins && ins->opcode == OP_REGOFFSET && MONO_TYPE_IS_REFERENCE (ins->inst_vtype))
411                         break;
412         }
413
414         if (i == cfg->num_varinfo)
415                 norefs = TRUE;
416
417         if (cfg->verbose_level > 1)
418                 printf ("GC Map for %s: 0x%x-0x%x\n", mono_method_full_name (cfg->method, TRUE), min_offset, max_offset);
419
420         nslots = (max_offset - min_offset) / sizeof (gpointer);
421         if (!norefs) {
422                 alloc_size = nslots * sizeof (StackSlotType);
423                 slots = mono_domain_alloc0 (cfg->domain, alloc_size);
424                 for (i = 0; i < nslots; ++i)
425                         slots [i] = SLOT_NOREF;
426                 gc_maps_size += alloc_size;
427         }
428         live_intervals = g_new0 (GSList*, nslots);
429         loffset = 0;
430
431         for (i = cfg->locals_start; i < cfg->num_varinfo; i++) {
432                 MonoInst *ins = cfg->varinfo [i];
433                 MonoType *t = ins->inst_vtype;
434                 MonoMethodVar *vmv;
435                 guint32 pos;
436
437                 if (norefs)
438                         continue;
439
440                 vmv = MONO_VARINFO (cfg, i);
441
442                 if (ins->opcode != OP_REGOFFSET)
443                         continue;
444
445                 if (ins->inst_offset % sizeof (gpointer) != 0)
446                         continue;
447
448                 pos = (ins->inst_offset - min_offset) / sizeof (gpointer);
449
450                 if ((MONO_TYPE_ISSTRUCT (t) && !ins->klass->has_references))
451                         continue;
452
453                 if ((MONO_TYPE_ISSTRUCT (t) && ins->klass->has_references)) {
454                         int numbits, j;
455                         gsize *bitmap;
456                         gboolean pin;
457
458                         if (ins->klass->generic_container || mono_class_is_open_constructed_type (t)) {
459                                 /* FIXME: Generic sharing */
460                                 pin = TRUE;
461                         } else {
462                                 mono_class_compute_gc_descriptor (ins->klass);
463
464                                 bitmap = mono_gc_get_bitmap_for_descr (ins->klass->gc_descr, &numbits);
465
466                                 if (bitmap) {
467                                         for (j = 0; j < numbits; ++j) {
468                                                 if (bitmap [j / GC_BITS_PER_WORD] & ((gsize)1 << (j % GC_BITS_PER_WORD))) {
469                                                         /* The descriptor is for the boxed object */
470                                                         set_slot (slots, nslots, (pos + j - (sizeof (MonoObject) / sizeof (gpointer))), SLOT_REF);
471                                                 }
472                                         }
473                                         g_free (bitmap);
474
475                                         if (cfg->verbose_level > 1)
476                                                 printf ("\tvtype at fp+0x%x: %s -> 0x%x\n", (int)ins->inst_offset, mono_type_full_name (ins->inst_vtype), (int)ins->inst_offset);
477
478                                         // FIXME: These have no live range
479                                         pin = TRUE;
480                                 } else {
481                                         // FIXME:
482                                         pin = TRUE;
483                                 }
484                         }
485
486                         if (ins->backend.is_pinvoke)
487                                 pin = TRUE;
488
489                         if (pin) {
490                                 int size;
491
492                                 if (ins->backend.is_pinvoke)
493                                         size = mono_class_native_size (ins->klass, NULL);
494                                 else
495                                         size = mono_class_value_size (ins->klass, NULL);
496                                 for (j = 0; j < size / sizeof (gpointer); ++j)
497                                         set_slot (slots, nslots, pos + j, SLOT_PIN);
498                         }
499                         continue;
500                 }
501
502                 if (ins->inst_offset < min_offset || ins->inst_offset >= max_offset)
503                         /* Vret addr etc. */
504                         continue;
505
506                 if (t->byref || t->type == MONO_TYPE_I) {
507                         // FIXME: JIT temporaries have type I
508                         set_slot (slots, nslots, pos, SLOT_PIN);
509                         continue;
510                 }
511
512                 if (MONO_TYPE_IS_REFERENCE (ins->inst_vtype)) {
513                         if (vmv && !vmv->gc_interval) {
514                                 set_slot (slots, nslots, pos, SLOT_PIN);
515                                 continue;
516                         }
517
518                         if (ins->flags & (MONO_INST_VOLATILE | MONO_INST_INDIRECT)) {
519                                 set_slot (slots, nslots, pos, SLOT_PIN);
520                                 continue;
521                         }
522
523                         set_slot (slots, nslots, pos, SLOT_REF);
524
525                         live_intervals [pos] = g_slist_prepend_mempool (cfg->mempool, live_intervals [pos], vmv->gc_interval);
526
527                         if (cfg->verbose_level > 1) {
528                                 printf ("\tref at %s0x%x(fp) (slot=%d): %s ", ins->inst_offset < 0 ? "-" : "", (ins->inst_offset < 0) ? -(int)ins->inst_offset : (int)ins->inst_offset, pos, mono_type_full_name (ins->inst_vtype));
529                                 mono_linterval_print (vmv->gc_interval);
530                                 printf ("\n");
531                         }
532                 }
533         }
534
535         loffset = 0;
536         if (slots) {
537                 for (i = 0; i < nslots; ++i) {
538                         if (slots [i] == SLOT_REF)
539                                 loffset ++;
540                 }
541         }
542
543         bitmap_width = ALIGN_TO (loffset, 8) / 8;
544         bitmap_size = bitmap_width * cfg->code_len;
545         alloc_size = sizeof (GCMap) + (norefs ? 0 : bitmap_size);
546         map = mono_domain_alloc0 (cfg->domain, alloc_size);
547         gc_maps_size += alloc_size;
548
549         map->frame_reg = cfg->frame_reg;
550         map->locals_offset = min_offset;
551         map->locals_size = ALIGN_TO (max_offset - min_offset, sizeof (gpointer));
552         map->nslots = nslots;
553         map->slots = slots;
554         map->bitmap_width = bitmap_width;
555
556         /* Create liveness bitmap */
557         loffset = 0;
558         if (slots) {
559                 for (i = 0; i < nslots; ++i) {
560                         if (map->slots [i] == SLOT_REF) {
561                                 MonoLiveInterval *iv;
562                                 GSList *l;
563                                 MonoLiveRange2 *r;
564                                 int pc_offset;
565
566                                 for (l = live_intervals [i]; l; l = l->next) {
567                                         iv = l->data;
568                                         for (r = iv->range; r; r = r->next) {
569                                                 for (pc_offset = r->from; pc_offset < r->to; ++pc_offset)
570                                                         map->bitmap [(map->bitmap_width * pc_offset) + loffset / 8] |= (1 << (loffset % 8));
571                                         }
572                                 }
573                                 loffset ++;
574                         }
575                 }
576         }
577
578 #if 1
579         {
580                 static int precise_count;
581
582                 if (map->slots) {
583                         precise_count ++;
584                         if (getenv ("MONO_GCMAP_COUNT")) {
585                                 if (precise_count == atoi (getenv ("MONO_GCMAP_COUNT")))
586                                         printf ("LAST: %s\n", mono_method_full_name (cfg->method, TRUE));
587                                 if (precise_count > atoi (getenv ("MONO_GCMAP_COUNT"))) {
588                                         for (i = 0; i < nslots; ++i)
589                                                 map->slots [i] = SLOT_PIN;
590                                 }
591                         }
592                 }
593         }
594 #endif
595
596         cfg->jit_info->gc_info = map;
597
598         g_free (live_intervals);
599 }
600
601 void
602 mini_gc_init (void)
603 {
604         MonoGCCallbacks cb;
605
606         memset (&cb, 0, sizeof (cb));
607         cb.thread_attach_func = thread_attach_func;
608         cb.thread_suspend_func = thread_suspend_func;
609         /* Comment this out to disable precise stack marking */
610         cb.thread_mark_func = thread_mark_func;
611         mono_gc_set_gc_callbacks (&cb);
612
613         mono_counters_register ("GC Maps size",
614                                                         MONO_COUNTER_GC | MONO_COUNTER_INT, &gc_maps_size);
615
616         mono_counters_register ("Stack space scanned (all)",
617                                                         MONO_COUNTER_GC | MONO_COUNTER_INT, &scanned_stacks_stat);
618         mono_counters_register ("Stack space scanned (using GC Maps)",
619                                                         MONO_COUNTER_GC | MONO_COUNTER_INT, &scanned_stat);
620         mono_counters_register ("Stack space scanned (precise)",
621                                                         MONO_COUNTER_GC | MONO_COUNTER_INT, &scanned_precisely_stat);
622         mono_counters_register ("Stack space scanned (conservative)",
623                                                         MONO_COUNTER_GC | MONO_COUNTER_INT, &scanned_conservatively_stat);
624 }
625
626 #else
627
628 void
629 mini_gc_init (void)
630 {
631 }
632
633 static void
634 mini_gc_init_gc_map (MonoCompile *cfg)
635 {
636 }
637
638 void
639 mini_gc_create_gc_map (MonoCompile *cfg)
640 {
641 }
642
643 #endif
644
645 /*
646  * mini_gc_init_cfg:
647  *
648  *   Set GC specific options in CFG.
649  */
650 void
651 mini_gc_init_cfg (MonoCompile *cfg)
652 {
653         if (mono_gc_is_moving ()) {
654                 cfg->disable_ref_noref_stack_slot_share = TRUE;
655                 cfg->gen_write_barriers = TRUE;
656         }
657
658         mini_gc_init_gc_map (cfg);
659 }
660
661 /*
662  * Problems with the current code:
663  * - it makes two passes over the stack
664  * - the stack walk is slow
665  * - only the locals are scanned precisely
666  * - vtypes/refs used in EH regions are treated conservatively
667  * - the computation of the GC maps is slow since it involves a liveness analysis pass
668  * - the GC maps are uncompressed and take up a lot of memory.
669  * - if the code is finished, less pinning will be done, causing problems because
670  *   we promote all surviving objects to old-gen.
671  */