a9a3d441a562d107e30dbcd031a9c2d283521311
[mono.git] / mono / mini / driver.c
1 /*
2  * driver.c: The new mono JIT compiler.
3  *
4  * Author:
5  *   Paolo Molaro (lupus@ximian.com)
6  *   Dietmar Maurer (dietmar@ximian.com)
7  *
8  * (C) 2002-2003 Ximian, Inc.
9  * (C) 2003-2006 Novell, Inc.
10  */
11
12 #include <config.h>
13 #include <signal.h>
14 #if HAVE_SCHED_SETAFFINITY
15 #include <sched.h>
16 #endif
17 #ifdef HAVE_UNISTD_H
18 #include <unistd.h>
19 #endif
20
21 #include <mono/metadata/assembly.h>
22 #include <mono/metadata/loader.h>
23 #include <mono/metadata/cil-coff.h>
24 #include <mono/metadata/tabledefs.h>
25 #include <mono/metadata/class.h>
26 #include <mono/metadata/object.h>
27 #include <mono/metadata/exception.h>
28 #include <mono/metadata/opcodes.h>
29 #include <mono/metadata/mono-endian.h>
30 #include <mono/metadata/tokentype.h>
31 #include <mono/metadata/tabledefs.h>
32 #include <mono/metadata/threads.h>
33 #include <mono/metadata/marshal.h>
34 #include <mono/metadata/socket-io.h>
35 #include <mono/metadata/appdomain.h>
36 #include <mono/metadata/debug-helpers.h>
37 #include <mono/io-layer/io-layer.h>
38 #include "mono/metadata/profiler.h"
39 #include <mono/metadata/profiler-private.h>
40 #include <mono/metadata/mono-config.h>
41 #include <mono/metadata/environment.h>
42 #include <mono/metadata/verify.h>
43 #include <mono/metadata/mono-debug.h>
44 #include <mono/metadata/security-manager.h>
45 #include <mono/metadata/security-core-clr.h>
46 #include <mono/os/gc_wrapper.h>
47 #include "mono/utils/mono-counters.h"
48
49 #include "mini.h"
50 #include "jit.h"
51 #include <string.h>
52 #include <ctype.h>
53 #include "inssel.h"
54 #include <locale.h>
55 #include "version.h"
56
57 static FILE *mini_stats_fd = NULL;
58
59 static void mini_usage (void);
60
61 /* This turns off command line globbing under win32 */
62 #ifdef PLATFORM_WIN32
63 int _CRT_glob = 0;
64 #endif
65
66 typedef void (*OptFunc) (const char *p);
67
68 #undef OPTFLAG
69 #ifdef HAVE_ARRAY_ELEM_INIT
70 #define MSGSTRFIELD(line) MSGSTRFIELD1(line)
71 #define MSGSTRFIELD1(line) str##line
72
73 static const struct msgstr_t {
74 #define OPTFLAG(id,shift,name,desc) char MSGSTRFIELD(__LINE__) [sizeof (name) + sizeof (desc)];
75 #include "optflags-def.h"
76 #undef OPTFLAG
77 } opstr = {
78 #define OPTFLAG(id,shift,name,desc) name "\0" desc,
79 #include "optflags-def.h"
80 #undef OPTFLAG
81 };
82 static const gint16 opt_names [] = {
83 #define OPTFLAG(id,shift,name,desc) [(shift)] = offsetof (struct msgstr_t, MSGSTRFIELD(__LINE__)),
84 #include "optflags-def.h"
85 #undef OPTFLAG
86 };
87
88 #define optflag_get_name(id) ((const char*)&opstr + opt_names [(id)])
89 #define optflag_get_desc(id) (optflag_get_name(id) + 1 + strlen (optflag_get_name(id)))
90
91 #else /* !HAVE_ARRAY_ELEM_INIT */
92 typedef struct {
93         const char* name;
94         const char* desc;
95 } OptName;
96
97 #define OPTFLAG(id,shift,name,desc) {name,desc},
98 static const OptName 
99 opt_names [] = {
100 #include "optflags-def.h"
101         {NULL, NULL}
102 };
103 #define optflag_get_name(id) (opt_names [(id)].name)
104 #define optflag_get_desc(id) (opt_names [(id)].desc)
105
106 #endif
107
108 static const OptFunc
109 opt_funcs [sizeof (int) * 8] = {
110         NULL
111 };
112
113 #define DEFAULT_OPTIMIZATIONS ( \
114         MONO_OPT_PEEPHOLE |     \
115         MONO_OPT_CFOLD |        \
116         MONO_OPT_INLINE |       \
117         MONO_OPT_CONSPROP |     \
118         MONO_OPT_COPYPROP |     \
119         MONO_OPT_TREEPROP |     \
120         MONO_OPT_DEADCE |       \
121         MONO_OPT_BRANCH |       \
122         MONO_OPT_LINEARS |      \
123         MONO_OPT_INTRINS |  \
124         MONO_OPT_LOOP |  \
125         MONO_OPT_EXCEPTION |  \
126         MONO_OPT_AOT)
127
128 #define EXCLUDED_FROM_ALL (MONO_OPT_SHARED | MONO_OPT_PRECOMP)
129
130 static guint32
131 parse_optimizations (const char* p)
132 {
133         /* the default value */
134         guint32 opt = DEFAULT_OPTIMIZATIONS;
135         guint32 exclude = 0;
136         const char *n;
137         int i, invert, len;
138
139         /* call out to cpu detection code here that sets the defaults ... */
140         opt |= mono_arch_cpu_optimizazions (&exclude);
141         opt &= ~exclude;
142         if (!p)
143                 return opt;
144
145         while (*p) {
146                 if (*p == '-') {
147                         p++;
148                         invert = TRUE;
149                 } else {
150                         invert = FALSE;
151                 }
152                 for (i = 0; i < G_N_ELEMENTS (opt_names) && optflag_get_name (i); ++i) {
153                         n = optflag_get_name (i);
154                         len = strlen (n);
155                         if (strncmp (p, n, len) == 0) {
156                                 if (invert)
157                                         opt &= ~ (1 << i);
158                                 else
159                                         opt |= 1 << i;
160                                 p += len;
161                                 if (*p == ',') {
162                                         p++;
163                                         break;
164                                 } else if (*p == '=') {
165                                         p++;
166                                         if (opt_funcs [i])
167                                                 opt_funcs [i] (p);
168                                         while (*p && *p++ != ',');
169                                         break;
170                                 }
171                                 /* error out */
172                                 break;
173                         }
174                 }
175                 if (i == G_N_ELEMENTS (opt_names) || !optflag_get_name (i)) {
176                         if (strncmp (p, "all", 3) == 0) {
177                                 if (invert)
178                                         opt = 0;
179                                 else
180                                         opt = ~(EXCLUDED_FROM_ALL | exclude);
181                                 p += 3;
182                                 if (*p == ',')
183                                         p++;
184                         } else {
185                                 fprintf (stderr, "Invalid optimization name `%s'\n", p);
186                                 exit (1);
187                         }
188                 }
189         }
190         return opt;
191 }
192
193 typedef struct {
194         const char name [6];
195         const char desc [18];
196         MonoGraphOptions value;
197 } GraphName;
198
199 static const GraphName 
200 graph_names [] = {
201         {"cfg",      "Control Flow",                            MONO_GRAPH_CFG},
202         {"dtree",    "Dominator Tree",                          MONO_GRAPH_DTREE},
203         {"code",     "CFG showing code",                        MONO_GRAPH_CFG_CODE},
204         {"ssa",      "CFG after SSA",                           MONO_GRAPH_CFG_SSA},
205         {"optc",     "CFG after IR opts",                       MONO_GRAPH_CFG_OPTCODE}
206 };
207
208 static MonoGraphOptions
209 mono_parse_graph_options (const char* p)
210 {
211         const char *n;
212         int i, len;
213
214         for (i = 0; i < G_N_ELEMENTS (graph_names); ++i) {
215                 n = graph_names [i].name;
216                 len = strlen (n);
217                 if (strncmp (p, n, len) == 0)
218                         return graph_names [i].value;
219         }
220
221         fprintf (stderr, "Invalid graph name provided: %s\n", p);
222         exit (1);
223 }
224
225 int
226 mono_parse_default_optimizations (const char* p)
227 {
228         guint32 opt;
229
230         opt = parse_optimizations (p);
231         return opt;
232 }
233
234 static char*
235 opt_descr (guint32 flags) {
236         GString *str = g_string_new ("");
237         int i, need_comma;
238
239         need_comma = 0;
240         for (i = 0; i < G_N_ELEMENTS (opt_names); ++i) {
241                 if (flags & (1 << i)) {
242                         if (need_comma)
243                                 g_string_append_c (str, ',');
244                         g_string_append (str, optflag_get_name (i));
245                         need_comma = 1;
246                 }
247         }
248         return g_string_free (str, FALSE);
249 }
250
251 static const guint32
252 opt_sets [] = {
253        0,
254        MONO_OPT_PEEPHOLE,
255        MONO_OPT_BRANCH,
256        MONO_OPT_CFOLD,
257        MONO_OPT_FCMOV,
258        MONO_OPT_BRANCH | MONO_OPT_PEEPHOLE | MONO_OPT_INTRINS,
259        MONO_OPT_BRANCH | MONO_OPT_PEEPHOLE | MONO_OPT_LINEARS,
260        MONO_OPT_BRANCH | MONO_OPT_PEEPHOLE | MONO_OPT_LINEARS | MONO_OPT_COPYPROP,
261        MONO_OPT_BRANCH | MONO_OPT_PEEPHOLE | MONO_OPT_LINEARS | MONO_OPT_CFOLD,
262        MONO_OPT_BRANCH | MONO_OPT_PEEPHOLE | MONO_OPT_LINEARS | MONO_OPT_COPYPROP | MONO_OPT_CONSPROP | MONO_OPT_DEADCE,
263        MONO_OPT_BRANCH | MONO_OPT_PEEPHOLE | MONO_OPT_LINEARS | MONO_OPT_COPYPROP | MONO_OPT_CONSPROP | MONO_OPT_DEADCE | MONO_OPT_LOOP | MONO_OPT_INLINE | MONO_OPT_INTRINS,
264        MONO_OPT_BRANCH | MONO_OPT_PEEPHOLE | MONO_OPT_LINEARS | MONO_OPT_COPYPROP | MONO_OPT_CONSPROP | MONO_OPT_DEADCE | MONO_OPT_LOOP | MONO_OPT_INLINE | MONO_OPT_INTRINS | MONO_OPT_SSA,
265        MONO_OPT_BRANCH | MONO_OPT_PEEPHOLE | MONO_OPT_LINEARS | MONO_OPT_COPYPROP | MONO_OPT_CONSPROP | MONO_OPT_DEADCE | MONO_OPT_LOOP | MONO_OPT_INLINE | MONO_OPT_INTRINS | MONO_OPT_EXCEPTION,
266        MONO_OPT_BRANCH | MONO_OPT_PEEPHOLE | MONO_OPT_LINEARS | MONO_OPT_COPYPROP | MONO_OPT_CONSPROP | MONO_OPT_DEADCE | MONO_OPT_LOOP | MONO_OPT_INLINE | MONO_OPT_INTRINS | MONO_OPT_EXCEPTION | MONO_OPT_ABCREM,
267        MONO_OPT_BRANCH | MONO_OPT_PEEPHOLE | MONO_OPT_LINEARS | MONO_OPT_COPYPROP | MONO_OPT_CONSPROP | MONO_OPT_DEADCE | MONO_OPT_LOOP | MONO_OPT_INLINE | MONO_OPT_INTRINS | MONO_OPT_EXCEPTION | MONO_OPT_ABCREM | MONO_OPT_SSAPRE,
268        MONO_OPT_BRANCH | MONO_OPT_PEEPHOLE | MONO_OPT_LINEARS | MONO_OPT_COPYPROP | MONO_OPT_CONSPROP | MONO_OPT_DEADCE | MONO_OPT_LOOP | MONO_OPT_INLINE | MONO_OPT_INTRINS | MONO_OPT_ABCREM,
269        MONO_OPT_BRANCH | MONO_OPT_PEEPHOLE | MONO_OPT_LINEARS | MONO_OPT_COPYPROP | MONO_OPT_CONSPROP | MONO_OPT_DEADCE | MONO_OPT_LOOP | MONO_OPT_INLINE | MONO_OPT_INTRINS | MONO_OPT_TREEPROP,
270        MONO_OPT_BRANCH | MONO_OPT_PEEPHOLE | MONO_OPT_LINEARS | MONO_OPT_COPYPROP | MONO_OPT_CONSPROP | MONO_OPT_DEADCE | MONO_OPT_LOOP | MONO_OPT_INLINE | MONO_OPT_INTRINS | MONO_OPT_SSAPRE,
271        MONO_OPT_BRANCH | MONO_OPT_PEEPHOLE | MONO_OPT_LINEARS | MONO_OPT_COPYPROP | MONO_OPT_CONSPROP | MONO_OPT_DEADCE | MONO_OPT_LOOP | MONO_OPT_INLINE | MONO_OPT_INTRINS | MONO_OPT_ABCREM | MONO_OPT_SHARED
272 };
273
274 typedef int (*TestMethod) (void);
275
276 #if 0
277 static void
278 domain_dump_native_code (MonoDomain *domain) {
279         // need to poke into the domain, move to metadata/domain.c
280         // need to empty jit_info_table and code_mp
281 }
282 #endif
283
284 static int
285 mini_regression (MonoImage *image, int verbose, int *total_run) {
286         guint32 i, opt, opt_flags;
287         MonoMethod *method;
288         MonoCompile *cfg;
289         char *n;
290         int result, expected, failed, cfailed, run, code_size, total;
291         TestMethod func;
292         GTimer *timer = g_timer_new ();
293
294         if (mini_stats_fd) {
295                 fprintf (mini_stats_fd, "$stattitle = \'Mono Benchmark Results (various optimizations)\';\n");
296
297                 fprintf (mini_stats_fd, "$graph->set_legend(qw(");
298                 for (opt = 0; opt < G_N_ELEMENTS (opt_sets); opt++) {
299                         opt_flags = opt_sets [opt];
300                         n = opt_descr (opt_flags);
301                         if (!n [0])
302                                 n = (char *)"none";
303                         if (opt)
304                                 fprintf (mini_stats_fd, " ");
305                         fprintf (mini_stats_fd, "%s", n);
306                 
307
308                 }
309                 fprintf (mini_stats_fd, "));\n");
310
311                 fprintf (mini_stats_fd, "@data = (\n");
312                 fprintf (mini_stats_fd, "[");
313         }
314
315         /* load the metadata */
316         for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
317                 method = mono_get_method (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL);
318                 mono_class_init (method->klass);
319
320                 if (!strncmp (method->name, "test_", 5) && mini_stats_fd) {
321                         fprintf (mini_stats_fd, "\"%s\",", method->name);
322                 }
323         }
324         if (mini_stats_fd)
325                 fprintf (mini_stats_fd, "],\n");
326
327
328         total = 0;
329         *total_run = 0;
330         for (opt = 0; opt < G_N_ELEMENTS (opt_sets); ++opt) {
331                 double elapsed, comp_time, start_time;
332
333                 opt_flags = opt_sets [opt];
334                 mono_set_defaults (verbose, opt_flags);
335                 n = opt_descr (opt_flags);
336                 g_print ("Test run: image=%s, opts=%s\n", mono_image_get_filename (image), n);
337                 g_free (n);
338                 cfailed = failed = run = code_size = 0;
339                 comp_time = elapsed = 0.0;
340
341                 /* fixme: ugly hack - delete all previously compiled methods */
342                 g_hash_table_destroy (mono_domain_get ()->jit_trampoline_hash);
343                 mono_domain_get ()->jit_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
344                 mono_internal_hash_table_destroy (&(mono_domain_get ()->jit_code_hash));
345                 mono_jit_code_hash_init (&(mono_domain_get ()->jit_code_hash));
346
347                 g_timer_start (timer);
348                 if (mini_stats_fd)
349                         fprintf (mini_stats_fd, "[");
350                 for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
351                         method = mono_get_method (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL);
352                         if (strncmp (method->name, "test_", 5) == 0) {
353                                 expected = atoi (method->name + 5);
354                                 run++;
355                                 start_time = g_timer_elapsed (timer, NULL);
356                                 comp_time -= start_time; 
357                                 cfg = mini_method_compile (method, opt_flags, mono_get_root_domain (), TRUE, FALSE, 0);
358                                 comp_time += g_timer_elapsed (timer, NULL);
359                                 if (cfg->exception_type == MONO_EXCEPTION_NONE) {
360                                         if (verbose >= 2)
361                                                 g_print ("Running '%s' ...\n", method->name);
362 #ifdef MONO_USE_AOT_COMPILER
363                                         if ((func = mono_aot_get_method (mono_get_root_domain (), method)))
364                                                 ;
365                                         else
366 #endif
367                                                 func = (TestMethod)(gpointer)cfg->native_code;
368                                         func = (TestMethod)mono_create_ftnptr (mono_get_root_domain (), func);
369                                         result = func ();
370                                         if (result != expected) {
371                                                 failed++;
372                                                 g_print ("Test '%s' failed result (got %d, expected %d).\n", method->name, result, expected);
373                                         }
374                                         code_size += cfg->code_len;
375                                         mono_destroy_compile (cfg);
376
377                                 } else {
378                                         cfailed++;
379                                         if (verbose)
380                                                 g_print ("Test '%s' failed compilation.\n", method->name);
381                                 }
382                                 if (mini_stats_fd)
383                                         fprintf (mini_stats_fd, "%f, ", 
384                                                  g_timer_elapsed (timer, NULL) - start_time);
385                         }
386                 }
387                 if (mini_stats_fd)
388                         fprintf (mini_stats_fd, "],\n");
389                 g_timer_stop (timer);
390                 elapsed = g_timer_elapsed (timer, NULL);
391                 if (failed > 0 || cfailed > 0){
392                         g_print ("Results: total tests: %d, failed: %d, cfailed: %d (pass: %.2f%%)\n", 
393                                  run, failed, cfailed, 100.0*(run-failed-cfailed)/run);
394                 } else {
395                         g_print ("Results: total tests: %d, all pass \n",  run);
396                 }
397                 
398                 g_print ("Elapsed time: %f secs (%f, %f), Code size: %d\n\n", elapsed, 
399                          elapsed - comp_time, comp_time, code_size);
400                 total += failed + cfailed;
401                 *total_run += run;
402         }
403
404         if (mini_stats_fd) {
405                 fprintf (mini_stats_fd, ");\n");
406                 fflush (mini_stats_fd);
407         }
408
409         g_timer_destroy (timer);
410         return total;
411 }
412
413 static int
414 mini_regression_list (int verbose, int count, char *images [])
415 {
416         int i, total, total_run, run;
417         MonoAssembly *ass;
418         
419         total_run =  total = 0;
420         for (i = 0; i < count; ++i) {
421                 ass = mono_assembly_open (images [i], NULL);
422                 if (!ass) {
423                         g_warning ("failed to load assembly: %s", images [i]);
424                         continue;
425                 }
426                 total += mini_regression (mono_assembly_get_image (ass), verbose, &run);
427                 total_run += run;
428         }
429         if (total > 0){
430                 g_print ("Overall results: tests: %d, failed: %d, opt combinations: %d (pass: %.2f%%)\n", 
431                          total_run, total, (int)G_N_ELEMENTS (opt_sets), 100.0*(total_run-total)/total_run);
432         } else {
433                 g_print ("Overall results: tests: %d, 100%% pass, opt combinations: %d\n", 
434                          total_run, (int)G_N_ELEMENTS (opt_sets));
435         }
436         
437         return total;
438 }
439
440 #ifdef MONO_JIT_INFO_TABLE_TEST
441 typedef struct _JitInfoData
442 {
443         guint start;
444         guint length;
445         MonoJitInfo *ji;
446         struct _JitInfoData *next;
447 } JitInfoData;
448
449 typedef struct
450 {
451         guint start;
452         guint length;
453         int num_datas;
454         JitInfoData *data;
455 } Region;
456
457 typedef struct
458 {
459         int num_datas;
460         int num_regions;
461         Region *regions;
462         int num_frees;
463         JitInfoData *frees;
464 } ThreadData;
465
466 static int num_threads;
467 static ThreadData *thread_datas;
468 static MonoDomain *test_domain;
469
470 static JitInfoData*
471 alloc_random_data (Region *region)
472 {
473         JitInfoData **data;
474         JitInfoData *prev;
475         guint prev_end;
476         guint next_start;
477         guint max_len;
478         JitInfoData *d;
479         int num_retries = 0;
480         int pos, i;
481
482  restart:
483         prev = NULL;
484         data = &region->data;
485         pos = random () % (region->num_datas + 1);
486         i = 0;
487         while (*data != NULL) {
488                 if (i++ == pos)
489                         break;
490                 prev = *data;
491                 data = &(*data)->next;
492         }
493
494         if (prev == NULL)
495                 g_assert (*data == region->data);
496         else
497                 g_assert (prev->next == *data);
498
499         if (prev == NULL)
500                 prev_end = region->start;
501         else
502                 prev_end = prev->start + prev->length;
503
504         if (*data == NULL)
505                 next_start = region->start + region->length;
506         else
507                 next_start = (*data)->start;
508
509         g_assert (prev_end <= next_start);
510
511         max_len = next_start - prev_end;
512         if (max_len < 128) {
513                 if (++num_retries >= 10)
514                         return NULL;
515                 goto restart;
516         }
517         if (max_len > 1024)
518                 max_len = 1024;
519
520         d = g_new0 (JitInfoData, 1);
521         d->start = prev_end + random () % (max_len / 2);
522         d->length = random () % MIN (max_len, next_start - d->start) + 1;
523
524         g_assert (d->start >= prev_end && d->start + d->length <= next_start);
525
526         d->ji = g_new0 (MonoJitInfo, 1);
527         d->ji->method = (MonoMethod*) 0xABadBabe;
528         d->ji->code_start = (gpointer)(gulong) d->start;
529         d->ji->code_size = d->length;
530         d->ji->cas_inited = 1;  /* marks an allocated jit info */
531
532         d->next = *data;
533         *data = d;
534
535         ++region->num_datas;
536
537         return d;
538 }
539
540 static JitInfoData**
541 choose_random_data (Region *region)
542 {
543         int n;
544         int i;
545         JitInfoData **d;
546
547         g_assert (region->num_datas > 0);
548
549         n = random () % region->num_datas;
550
551         for (d = &region->data, i = 0;
552              i < n;
553              d = &(*d)->next, ++i)
554                 ;
555
556         return d;
557 }
558
559 static Region*
560 choose_random_region (ThreadData *td)
561 {
562         return &td->regions [random () % td->num_regions];
563 }
564
565 static ThreadData*
566 choose_random_thread (void)
567 {
568         return &thread_datas [random () % num_threads];
569 }
570
571 static void
572 free_jit_info_data (ThreadData *td, JitInfoData *free)
573 {
574         free->next = td->frees;
575         td->frees = free;
576
577         if (++td->num_frees >= 1000) {
578                 int i;
579
580                 for (i = 0; i < 500; ++i)
581                         free = free->next;
582
583                 while (free->next != NULL) {
584                         JitInfoData *next = free->next->next;
585
586                         g_free (free->next->ji);
587                         g_free (free->next);
588                         free->next = next;
589
590                         --td->num_frees;
591                 }
592         }
593 }
594
595 #define NUM_THREADS             8
596 #define REGIONS_PER_THREAD      10
597 #define REGION_SIZE             0x10000
598
599 #define MAX_ADDR                (REGION_SIZE * REGIONS_PER_THREAD * NUM_THREADS)
600
601 #define MODE_ALLOC      1
602 #define MODE_FREE       2
603
604 static void
605 test_thread_func (ThreadData *td)
606 {
607         int mode = MODE_ALLOC;
608         int i = 0;
609         gulong lookup_successes = 0, lookup_failures = 0;
610         MonoDomain *domain = test_domain;
611         int thread_num = (int)(td - thread_datas);
612         gboolean modify_thread = thread_num < NUM_THREADS / 2; /* only half of the threads modify the table */
613
614         for (;;) {
615                 int alloc;
616                 int lookup = 1;
617
618                 if (td->num_datas == 0) {
619                         lookup = 0;
620                         alloc = 1;
621                 } else if (modify_thread && random () % 1000 < 5) {
622                         lookup = 0;
623                         if (mode == MODE_ALLOC)
624                                 alloc = (random () % 100) < 70;
625                         else if (mode == MODE_FREE)
626                                 alloc = (random () % 100) < 30;
627                 }
628
629                 if (lookup) {
630                         /* modify threads sometimes look up their own jit infos */
631                         if (modify_thread && random () % 10 < 5) {
632                                 Region *region = choose_random_region (td);
633
634                                 if (region->num_datas > 0) {
635                                         JitInfoData **data = choose_random_data (region);
636                                         guint pos = (*data)->start + random () % (*data)->length;
637                                         MonoJitInfo *ji = mono_jit_info_table_find (domain, (char*)(gulong) pos);
638
639                                         g_assert ((*data)->ji == ji);
640                                         g_assert (ji->cas_inited);
641                                 }
642                         } else {
643                                 int pos = random () % MAX_ADDR;
644                                 char *addr = (char*)(gulong) pos;
645                                 MonoJitInfo *ji = mono_jit_info_table_find (domain, addr);
646
647                                 if (ji != NULL) {
648                                         g_assert (addr >= (char*)ji->code_start && addr < (char*)ji->code_start + ji->code_size);
649                                         ++lookup_successes;
650                                 } else
651                                         ++lookup_failures;
652                         }
653                 } else if (alloc) {
654                         JitInfoData *data = alloc_random_data (choose_random_region (td));
655
656                         if (data != NULL) {
657                                 mono_jit_info_table_add (domain, data->ji);
658
659                                 ++td->num_datas;
660                         }
661                 } else {
662                         Region *region = choose_random_region (td);
663
664                         if (region->num_datas > 0) {
665                                 JitInfoData **data = choose_random_data (region);
666                                 JitInfoData *free;
667
668                                 mono_jit_info_table_remove (domain, (*data)->ji);
669
670                                 (*data)->ji->cas_inited = 0; /* marks a free jit info */
671
672                                 free = *data;
673                                 *data = (*data)->next;
674
675                                 free_jit_info_data (td, free);
676
677                                 --region->num_datas;
678                                 --td->num_datas;
679                         }
680                 }
681
682                 if (++i % 100000 == 0) {
683                         int j;
684                         g_print ("num datas %d (%ld - %ld): %d", (int)(td - thread_datas),
685                                  lookup_successes, lookup_failures, td->num_datas);
686                         for (j = 0; j < td->num_regions; ++j)
687                                 g_print ("  %d", td->regions [j].num_datas);
688                         g_print ("\n");
689                 }
690
691                 if (td->num_datas < 100)
692                         mode = MODE_ALLOC;
693                 else if (td->num_datas > 2000)
694                         mode = MODE_FREE;
695         }
696 }
697
698 /*
699 static void
700 small_id_thread_func (gpointer arg)
701 {
702         MonoThread *thread = mono_thread_current ();
703         MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
704
705         g_print ("my small id is %d\n", (int)thread->small_id);
706         mono_hazard_pointer_clear (hp, 1);
707         sleep (3);
708         g_print ("done %d\n", (int)thread->small_id);
709 }
710 */
711
712 static void
713 jit_info_table_test (MonoDomain *domain)
714 {
715         int i;
716
717         g_print ("testing jit_info_table\n");
718
719         num_threads = NUM_THREADS;
720         thread_datas = g_new0 (ThreadData, num_threads);
721
722         for (i = 0; i < num_threads; ++i) {
723                 int j;
724
725                 thread_datas [i].num_regions = REGIONS_PER_THREAD;
726                 thread_datas [i].regions = g_new0 (Region, REGIONS_PER_THREAD);
727
728                 for (j = 0; j < REGIONS_PER_THREAD; ++j) {
729                         thread_datas [i].regions [j].start = (num_threads * j + i) * REGION_SIZE;
730                         thread_datas [i].regions [j].length = REGION_SIZE;
731                 }
732         }
733
734         test_domain = domain;
735
736         /*
737         for (i = 0; i < 72; ++i)
738                 mono_thread_create (domain, small_id_thread_func, NULL);
739
740         sleep (2);
741         */
742
743         for (i = 0; i < num_threads; ++i)
744                 mono_thread_create (domain, test_thread_func, &thread_datas [i]);
745 }
746 #endif
747
748 enum {
749         DO_BENCH,
750         DO_REGRESSION,
751         DO_COMPILE,
752         DO_EXEC,
753         DO_DRAW,
754         DO_DEBUGGER
755 };
756
757 typedef struct CompileAllThreadArgs {
758         MonoAssembly *ass;
759         int verbose;
760         guint32 opts;
761 } CompileAllThreadArgs;
762
763 static void
764 compile_all_methods_thread_main (CompileAllThreadArgs *args)
765 {
766         MonoAssembly *ass = args->ass;
767         int verbose = args->verbose;
768         MonoImage *image = mono_assembly_get_image (ass);
769         MonoMethod *method;
770         MonoCompile *cfg;
771         int i, count = 0;
772
773         for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
774                 guint32 token = MONO_TOKEN_METHOD_DEF | (i + 1);
775                 MonoMethodSignature *sig;
776
777                 if (mono_metadata_has_generic_params (image, token))
778                         continue;
779
780                 method = mono_get_method (image, token, NULL);
781                 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
782                     (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
783                     (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
784                     (method->flags & METHOD_ATTRIBUTE_ABSTRACT))
785                         continue;
786
787                 if (method->klass->generic_container)
788                         continue;
789                 sig = mono_method_signature (method);
790                 if (sig->has_type_parameters)
791                         continue;
792
793                 count++;
794                 if (verbose) {
795                         char * desc = mono_method_full_name (method, TRUE);
796                         g_print ("Compiling %d %s\n", count, desc);
797                         g_free (desc);
798                 }
799                 cfg = mini_method_compile (method, args->opts, mono_get_root_domain (), FALSE, FALSE, 0);
800                 mono_destroy_compile (cfg);
801         }
802
803 }
804
805 static void
806 compile_all_methods (MonoAssembly *ass, int verbose, guint32 opts)
807 {
808         CompileAllThreadArgs args;
809
810         args.ass = ass;
811         args.verbose = verbose;
812         args.opts = opts;
813
814         /* 
815          * Need to create a mono thread since compilation might trigger
816          * running of managed code.
817          */
818         mono_thread_create (mono_domain_get (), compile_all_methods_thread_main, &args);
819
820         mono_thread_manage ();
821 }
822
823 /**
824  * mono_jit_exec:
825  * @assembly: reference to an assembly
826  * @argc: argument count
827  * @argv: argument vector
828  *
829  * Start execution of a program.
830  */
831 int 
832 mono_jit_exec (MonoDomain *domain, MonoAssembly *assembly, int argc, char *argv[])
833 {
834         MonoImage *image = mono_assembly_get_image (assembly);
835         MonoMethod *method;
836         guint32 entry = mono_image_get_entry_point (image);
837
838         if (!entry) {
839                 g_print ("Assembly '%s' doesn't have an entry point.\n", mono_image_get_filename (image));
840                 /* FIXME: remove this silly requirement. */
841                 mono_environment_exitcode_set (1);
842                 return 1;
843         }
844
845         method = mono_get_method (image, entry, NULL);
846         if (method == NULL){
847                 g_print ("The entry point method could not be loaded\n");
848                 mono_environment_exitcode_set (1);
849                 return 1;
850         }
851         
852         return mono_runtime_run_main (method, argc, argv, NULL);
853 }
854
855 typedef struct 
856 {
857         MonoDomain *domain;
858         const char *file;
859         int argc;
860         char **argv;
861         guint32 opts;
862         char *aot_options;
863 } MainThreadArgs;
864
865 static void main_thread_handler (gpointer user_data)
866 {
867         MainThreadArgs *main_args = user_data;
868         MonoAssembly *assembly;
869
870         assembly = mono_domain_assembly_open (main_args->domain, main_args->file);
871         if (!assembly){
872                 fprintf (stderr, "Can not open image %s\n", main_args->file);
873                 exit (1);
874         }
875
876         if (mono_compile_aot) {
877                 int res = mono_compile_assembly (assembly, main_args->opts, main_args->aot_options);
878                 printf ("AOT RESULT %d\n", res);
879         } else {
880                 /* 
881                  * This must be done in a thread managed by mono since it can invoke
882                  * managed code.
883                  */
884                 if (main_args->opts & MONO_OPT_PRECOMP)
885                         mono_precompile_assemblies ();
886
887                 mono_jit_exec (main_args->domain, assembly, main_args->argc, main_args->argv);
888         }
889 }
890
891 static void
892 mini_usage_jitdeveloper (void)
893 {
894         int i;
895         
896         fprintf (stdout,
897                  "Runtime and JIT debugging options:\n"
898                  "    --breakonex            Inserts a breakpoint on exceptions\n"
899                  "    --break METHOD         Inserts a breakpoint at METHOD entry\n"
900                  "    --compile METHOD       Just compile METHOD in assembly\n"
901                  "    --compile-all          Compiles all the methods in the assembly\n"
902                  "    --ncompile N           Number of times to compile METHOD (default: 1)\n"
903                  "    --print-vtable         Print the vtable of all used classes\n"
904                  "    --regression           Runs the regression test contained in the assembly\n"
905                  "    --statfile FILE        Sets the stat file to FILE\n"
906                  "    --stats                Print statistics about the JIT operations\n"
907                  "    --wapi=hps|semdel      IO-layer maintenance\n"
908                  "\n"
909                  "Other options:\n" 
910                  "    --graph[=TYPE] METHOD  Draws a graph of the specified method:\n");
911         
912         for (i = 0; i < G_N_ELEMENTS (graph_names); ++i) {
913                 fprintf (stdout, "                           %-10s %s\n", graph_names [i].name, graph_names [i].desc);
914         }
915 }
916
917 static void
918 mini_usage_list_opt (void)
919 {
920         int i;
921         
922         for (i = 0; i < G_N_ELEMENTS (opt_names); ++i)
923                 fprintf (stdout, "                           %-10s %s\n", optflag_get_name (i), optflag_get_desc (i));
924 }
925
926 static void
927 mini_usage (void)
928 {
929         fprintf (stdout,
930                 "Usage is: mono [options] program [program-options]\n"
931                 "\n"
932                 "Development:\n"
933                 "    --aot                  Compiles the assembly to native code\n"
934                 "    --debug                Enable debugging support\n"
935                 "    --profile[=profiler]   Runs in profiling mode with the specified profiler module\n"
936                 "    --trace[=EXPR]         Enable tracing, use --help-trace for details\n"
937                 "    --help-devel           Shows more options available to developers\n"
938                 "\n"
939                 "Runtime:\n"
940                 "    --config FILE          Loads FILE as the Mono config\n"
941                 "    --verbose, -v          Increases the verbosity level\n"
942                 "    --help, -h             Show usage information\n"
943                 "    --version, -V          Show version information\n"
944                 "    --runtime=VERSION      Use the VERSION runtime, instead of autodetecting\n"
945                 "    --optimize=OPT         Turns on or off a specific optimization\n"
946                 "                           Use --list-opt to get a list of optimizations\n"
947                 "    --security[=mode]      Turns on the unsupported security manager (off by default)\n"
948                 "                           mode is one of cas or core-clr\n");
949 }
950
951 static void
952 mini_trace_usage (void)
953 {
954         fprintf (stdout,
955                  "Tracing options:\n"
956                  "   --trace[=EXPR]        Trace every call, optional EXPR controls the scope\n"
957                  "\n"
958                  "EXPR is composed of:\n"
959                  "    all                  All assemblies\n"
960                  "    none                 No assemblies\n"
961                  "    program              Entry point assembly\n"
962                  "    assembly             Specifies an assembly\n"
963                  "    M:Type:Method        Specifies a method\n"
964                  "    N:Namespace          Specifies a namespace\n"
965                  "    T:Type               Specifies a type\n"
966                  "    +EXPR                Includes expression\n"
967                  "    -EXPR                Excludes expression\n"
968                  "    disabled             Don't print any output until toggled via SIGUSR2\n");
969 }
970
971 static const char info[] =
972 #ifdef HAVE_KW_THREAD
973         "\tTLS:           __thread\n"
974 #else
975         "\tTLS:           normal\n"
976 #endif /* HAVE_KW_THREAD */
977         "\tGC:            " USED_GC_NAME "\n"
978 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
979     "\tSIGSEGV:       altstack\n"
980 #else
981     "\tSIGSEGV:       normal\n"
982 #endif
983 #ifdef HAVE_EPOLL
984     "\tNotifications: epoll\n"
985 #else
986     "\tNotification:  Thread + polling\n"
987 #endif
988         "\tArchitecture:  " ARCHITECTURE "\n"
989         "\tDisabled:      " DISABLED_FEATURES "\n"
990         "";
991
992 #ifndef MONO_ARCH_AOT_SUPPORTED
993 #define error_if_aot_unsupported() do {fprintf (stderr, "AOT compilation is not supported on this platform.\n"); exit (1);} while (0)
994 #else
995 #define error_if_aot_unsupported()
996 #endif
997
998 int
999 mono_main (int argc, char* argv[])
1000 {
1001         MainThreadArgs main_args;
1002         MonoAssembly *assembly;
1003         MonoMethodDesc *desc;
1004         MonoMethod *method;
1005         MonoCompile *cfg;
1006         MonoDomain *domain;
1007         const char* aname, *mname = NULL;
1008         char *config_file = NULL;
1009         int i, count = 1;
1010         int enable_debugging = FALSE;
1011         guint32 opt, action = DO_EXEC;
1012         MonoGraphOptions mono_graph_options = 0;
1013         int mini_verbose = 0;
1014         gboolean enable_profile = FALSE;
1015         char *trace_options = NULL;
1016         char *profile_options = NULL;
1017         char *aot_options = NULL;
1018         char *forced_version = NULL;
1019 #ifdef MONO_JIT_INFO_TABLE_TEST
1020         int test_jit_info_table = FALSE;
1021 #endif
1022
1023         setlocale (LC_ALL, "");
1024
1025 #if HAVE_SCHED_SETAFFINITY
1026         if (getenv ("MONO_NO_SMP")) {
1027                 unsigned long proc_mask = 1;
1028                 sched_setaffinity (getpid(), sizeof (unsigned long), &proc_mask);
1029         }
1030 #endif
1031         if (!g_thread_supported ())
1032                 g_thread_init (NULL);
1033
1034         if (mono_running_on_valgrind () && getenv ("MONO_VALGRIND_LEAK_CHECK")) {
1035                 GMemVTable mem_vtable;
1036
1037                 /* 
1038                  * Instruct glib to use the system allocation functions so valgrind
1039                  * can track the memory allocated by the g_... functions.
1040                  */
1041                 memset (&mem_vtable, 0, sizeof (mem_vtable));
1042                 mem_vtable.malloc = malloc;
1043                 mem_vtable.realloc = realloc;
1044                 mem_vtable.free = free;
1045                 mem_vtable.calloc = calloc;
1046
1047                 g_mem_set_vtable (&mem_vtable);
1048         }
1049
1050         g_log_set_always_fatal (G_LOG_LEVEL_ERROR);
1051         g_log_set_fatal_mask (G_LOG_DOMAIN, G_LOG_LEVEL_ERROR);
1052
1053         opt = parse_optimizations (NULL);
1054
1055         for (i = 1; i < argc; ++i) {
1056                 if (argv [i] [0] != '-')
1057                         break;
1058                 if (strcmp (argv [i], "--regression") == 0) {
1059                         action = DO_REGRESSION;
1060                 } else if (strcmp (argv [i], "--verbose") == 0 || strcmp (argv [i], "-v") == 0) {
1061                         mini_verbose++;
1062                 } else if (strcmp (argv [i], "--version") == 0 || strcmp (argv [i], "-V") == 0) {
1063                         g_print ("Mono JIT compiler version %s (%s)\nCopyright (C) 2002-2007 Novell, Inc and Contributors. www.mono-project.com\n", VERSION, FULL_VERSION);
1064                         g_print (info);
1065                         if (mini_verbose) {
1066                                 const char *cerror;
1067                                 const char *clibpath;
1068                                 mono_init ("mono");
1069                                 cerror = mono_check_corlib_version ();
1070                                 clibpath = mono_defaults.corlib? mono_image_get_filename (mono_defaults.corlib): "unknown";
1071                                 if (cerror) {
1072                                         g_print ("The currently installed mscorlib doesn't match this runtime version.\n");
1073                                         g_print ("The error is: %s\n", cerror);
1074                                         g_print ("mscorlib.dll loaded at: %s\n", clibpath);
1075                                         return 1;
1076                                 }
1077                         }
1078                         return 0;
1079                 } else if (strcmp (argv [i], "--help") == 0 || strcmp (argv [i], "-h") == 0) {
1080                         mini_usage ();
1081                         return 0;
1082                 } else if (strcmp (argv [i], "--help-trace") == 0){
1083                         mini_trace_usage ();
1084                         return 0;
1085                 } else if (strcmp (argv [i], "--help-devel") == 0){
1086                         mini_usage_jitdeveloper ();
1087                         return 0;
1088                 } else if (strcmp (argv [i], "--list-opt") == 0){
1089                         mini_usage_list_opt ();
1090                         return 0;
1091                 } else if (strncmp (argv [i], "--statfile", 10) == 0) {
1092                         if (i + 1 >= argc){
1093                                 fprintf (stderr, "error: --statfile requires a filename argument\n");
1094                                 return 1;
1095                         }
1096                         mini_stats_fd = fopen (argv [++i], "w+");
1097                 } else if (strncmp (argv [i], "--optimize=", 11) == 0) {
1098                         opt = parse_optimizations (argv [i] + 11);
1099                 } else if (strncmp (argv [i], "-O=", 3) == 0) {
1100                         opt = parse_optimizations (argv [i] + 3);
1101                 } else if (strcmp (argv [i], "--config") == 0) {
1102                         if (i +1 >= argc){
1103                                 fprintf (stderr, "error: --config requires a filename argument\n");
1104                                 return 1;
1105                         }
1106                         config_file = argv [++i];
1107                 } else if (strcmp (argv [i], "--ncompile") == 0) {
1108                         if (i + 1 >= argc){
1109                                 fprintf (stderr, "error: --ncompile requires an argument\n");
1110                                 return 1;
1111                         }
1112                         count = atoi (argv [++i]);
1113                         action = DO_BENCH;
1114                 } else if (strcmp (argv [i], "--trace") == 0) {
1115                         trace_options = (char*)"";
1116                 } else if (strncmp (argv [i], "--trace=", 8) == 0) {
1117                         trace_options = &argv [i][8];
1118                 } else if (strcmp (argv [i], "--breakonex") == 0) {
1119                         mono_break_on_exc = TRUE;
1120                 } else if (strcmp (argv [i], "--break") == 0) {
1121                         if (i+1 >= argc){
1122                                 fprintf (stderr, "Missing method name in --break command line option\n");
1123                                 return 1;
1124                         }
1125                         
1126                         if (!mono_debugger_insert_breakpoint (argv [++i], FALSE))
1127                                 fprintf (stderr, "Error: invalid method name '%s'\n", argv [i]);
1128                 } else if (strcmp (argv [i], "--print-vtable") == 0) {
1129                         mono_print_vtable = TRUE;
1130                 } else if (strcmp (argv [i], "--stats") == 0) {
1131                         mono_counters_enable (-1);
1132                         mono_stats.enabled = TRUE;
1133                         mono_jit_stats.enabled = TRUE;
1134 #ifndef DISABLE_AOT
1135                 } else if (strcmp (argv [i], "--aot") == 0) {
1136                         error_if_aot_unsupported ();
1137                         mono_compile_aot = TRUE;
1138                 } else if (strncmp (argv [i], "--aot=", 6) == 0) {
1139                         error_if_aot_unsupported ();
1140                         mono_compile_aot = TRUE;
1141                         aot_options = &argv [i][6];
1142 #endif
1143                 } else if (strcmp (argv [i], "--compile-all") == 0) {
1144                         action = DO_COMPILE;
1145                 } else if (strncmp (argv [i], "--runtime=", 10) == 0) {
1146                         forced_version = &argv [i][10];
1147                 } else if (strcmp (argv [i], "--profile") == 0) {
1148                         enable_profile = TRUE;
1149                         profile_options = NULL;
1150                 } else if (strncmp (argv [i], "--profile=", 10) == 0) {
1151                         enable_profile = TRUE;
1152                         profile_options = argv [i] + 10;
1153                 } else if (strcmp (argv [i], "--compile") == 0) {
1154                         if (i + 1 >= argc){
1155                                 fprintf (stderr, "error: --compile option requires a method name argument\n");
1156                                 return 1;
1157                         }
1158                         
1159                         mname = argv [++i];
1160                         action = DO_BENCH;
1161                 } else if (strncmp (argv [i], "--graph=", 8) == 0) {
1162                         if (i + 1 >= argc){
1163                                 fprintf (stderr, "error: --graph option requires a method name argument\n");
1164                                 return 1;
1165                         }
1166                         
1167                         mono_graph_options = mono_parse_graph_options (argv [i] + 8);
1168                         mname = argv [++i];
1169                         action = DO_DRAW;
1170                 } else if (strcmp (argv [i], "--graph") == 0) {
1171                         if (i + 1 >= argc){
1172                                 fprintf (stderr, "error: --graph option requires a method name argument\n");
1173                                 return 1;
1174                         }
1175                         
1176                         mname = argv [++i];
1177                         mono_graph_options = MONO_GRAPH_CFG;
1178                         action = DO_DRAW;
1179                 } else if (strcmp (argv [i], "--debug") == 0) {
1180                         enable_debugging = TRUE;
1181                 } else if (strcmp (argv [i], "--security") == 0) {
1182                         mono_security_set_mode (MONO_SECURITY_MODE_CAS);
1183                         mono_activate_security_manager ();
1184                 } else if (strncmp (argv [i], "--security=", 11) == 0) {
1185                         if (strcmp (argv [i] + 11, "temporary-smcs-hack") == 0) {
1186                                 mono_security_set_mode (MONO_SECURITY_MODE_SMCS_HACK);
1187                         } else if (strcmp (argv [i] + 11, "core-clr") == 0) {
1188                                 mono_security_set_mode (MONO_SECURITY_MODE_CORE_CLR);
1189                         } else if (strcmp (argv [i] + 11, "core-clr-test") == 0) {
1190                                 mono_security_set_mode (MONO_SECURITY_MODE_CORE_CLR);
1191                                 mono_security_core_clr_test = TRUE;
1192                         } else if (strcmp (argv [i] + 11, "cas") == 0){
1193                                 mono_security_set_mode (MONO_SECURITY_MODE_CAS);
1194                                 mono_activate_security_manager ();
1195                         } else {
1196                                 fprintf (stderr, "error: --security= option has invalid argument (cas or core-clr)\n");
1197                                 return 1;
1198                         }
1199                 } else if (strcmp (argv [i], "--desktop") == 0) {
1200 #if defined (HAVE_BOEHM_GC)
1201                         GC_dont_expand = 1;
1202 #endif
1203                         /* Put desktop-specific optimizations here */
1204                 } else if (strcmp (argv [i], "--server") == 0){
1205                         /* Put server-specific optimizations here */
1206                 } else if (strcmp (argv [i], "--inside-mdb") == 0) {
1207                         action = DO_DEBUGGER;
1208                 } else if (strncmp (argv [i], "--wapi=", 7) == 0) {
1209                         if (strcmp (argv [i] + 7, "hps") == 0) {
1210                                 return mini_wapi_hps (argc - i, argv + i);
1211                         } else if (strcmp (argv [i] + 7, "semdel") == 0) {
1212                                 return mini_wapi_semdel (argc - i, argv + i);
1213                         } else if (strcmp (argv [i] + 7, "seminfo") == 0) {
1214                                 return mini_wapi_seminfo (argc - i, argv + i);
1215                         } else {
1216                                 fprintf (stderr, "Invalid --wapi suboption: '%s'\n", argv [i]);
1217                                 return 1;
1218                         }
1219 #ifdef MONO_JIT_INFO_TABLE_TEST
1220                 } else if (strcmp (argv [i], "--test-jit-info-table") == 0) {
1221                         test_jit_info_table = TRUE;
1222 #endif
1223                 } else {
1224                         fprintf (stderr, "Unknown command line option: '%s'\n", argv [i]);
1225                         return 1;
1226                 }
1227         }
1228
1229         if (!argv [i]) {
1230                 mini_usage ();
1231                 return 1;
1232         }
1233
1234         if ((action == DO_EXEC) && g_getenv ("MONO_INSIDE_MDB"))
1235                 action = DO_DEBUGGER;
1236
1237         if (mono_compile_aot || action == DO_EXEC || action == DO_DEBUGGER) {
1238                 g_set_prgname (argv[i]);
1239         }
1240
1241         if (enable_profile) {
1242                 /* Needed because of TLS accesses in mono_profiler_load () */
1243                 MONO_GC_PRE_INIT ();
1244                 mono_profiler_load (profile_options);
1245         }
1246
1247         if (trace_options != NULL){
1248                 /* 
1249                  * Need to call this before mini_init () so we can trace methods 
1250                  * compiled there too.
1251                  */
1252                 mono_jit_trace_calls = mono_trace_parse_options (trace_options);
1253                 if (mono_jit_trace_calls == NULL)
1254                         exit (1);
1255         }
1256
1257         if (action == DO_DEBUGGER) {
1258                 // opt |= MONO_OPT_SHARED;
1259                 opt &= ~MONO_OPT_INLINE;
1260                 opt &= ~MONO_OPT_COPYPROP;
1261                 opt &= ~MONO_OPT_CONSPROP;
1262                 enable_debugging = TRUE;
1263
1264 #ifdef MONO_DEBUGGER_SUPPORTED
1265                 mono_debug_init (MONO_DEBUG_FORMAT_DEBUGGER);
1266                 mono_debugger_init ();
1267 #else
1268                 g_print ("The Mono Debugger is not supported on this platform.\n");
1269                 return 1;
1270 #endif
1271         }
1272
1273         mono_set_defaults (mini_verbose, opt);
1274         domain = mini_init (argv [i], forced_version);
1275         
1276         switch (action) {
1277         case DO_REGRESSION:
1278                 if (mini_regression_list (mini_verbose, argc -i, argv + i)) {
1279                         g_print ("Regression ERRORS!\n");
1280                         mini_cleanup (domain);
1281                         return 1;
1282                 }
1283                 mini_cleanup (domain);
1284                 return 0;
1285         case DO_BENCH:
1286                 if (argc - i != 1 || mname == NULL) {
1287                         g_print ("Usage: mini --ncompile num --compile method assembly\n");
1288                         mini_cleanup (domain);
1289                         return 1;
1290                 }
1291                 aname = argv [i];
1292                 break;
1293         case DO_COMPILE:
1294                 if (argc - i != 1) {
1295                         mini_usage ();
1296                         mini_cleanup (domain);
1297                         return 1;
1298                 }
1299                 aname = argv [i];
1300                 break;
1301         case DO_DRAW:
1302                 if (argc - i != 1 || mname == NULL) {
1303                         mini_usage ();
1304                         mini_cleanup (domain);
1305                         return 1;
1306                 }
1307                 aname = argv [i];
1308                 break;
1309         default:
1310                 if (argc - i < 1) {
1311                         mini_usage ();
1312                         mini_cleanup (domain);
1313                         return 1;
1314                 }
1315                 aname = argv [i];
1316                 break;
1317         }
1318
1319         if (action == DO_DEBUGGER)
1320                 mono_debug_init_1 (domain);
1321         else if (enable_debugging) {
1322                 mono_debug_init (MONO_DEBUG_FORMAT_MONO);
1323                 mono_debug_init_1 (domain);
1324         }
1325
1326         /* Parse gac loading options before loading assemblies. */
1327         if (mono_compile_aot || action == DO_EXEC || action == DO_DEBUGGER) {
1328                 mono_config_parse (config_file);
1329         }
1330
1331 #ifdef MONO_JIT_INFO_TABLE_TEST
1332         if (test_jit_info_table)
1333                 jit_info_table_test (domain);
1334 #endif
1335
1336         assembly = mono_assembly_open (aname, NULL);
1337         if (!assembly) {
1338                 fprintf (stderr, "Cannot open assembly %s.\n", aname);
1339                 mini_cleanup (domain);
1340                 return 2;
1341         }
1342
1343         if (trace_options != NULL)
1344                 mono_trace_set_assembly (assembly);
1345
1346         if (enable_debugging)
1347                 mono_debug_init_2 (assembly);
1348
1349         if (mono_compile_aot || action == DO_EXEC) {
1350                 const char *error;
1351
1352                 //mono_set_rootdir ();
1353
1354                 error = mono_check_corlib_version ();
1355                 if (error) {
1356                         fprintf (stderr, "Corlib not in sync with this runtime: %s\n", error);
1357                         fprintf (stderr, "Loaded from: %s\n",
1358                                 mono_defaults.corlib? mono_image_get_filename (mono_defaults.corlib): "unknown");
1359                         fprintf (stderr, "Download a newer corlib or a newer runtime at http://www.go-mono.com/daily.\n");
1360                         exit (1);
1361                 }
1362
1363 #ifdef PLATFORM_WIN32
1364                 /* Detach console when executing IMAGE_SUBSYSTEM_WINDOWS_GUI on win32 */
1365                 if (!enable_debugging && !mono_compile_aot && ((MonoCLIImageInfo*)(mono_assembly_get_image (assembly)->image_info))->cli_header.nt.pe_subsys_required == IMAGE_SUBSYSTEM_WINDOWS_GUI)
1366                         FreeConsole ();
1367 #endif
1368
1369                 main_args.domain = domain;
1370                 main_args.file = aname;         
1371                 main_args.argc = argc - i;
1372                 main_args.argv = argv + i;
1373                 main_args.opts = opt;
1374                 main_args.aot_options = aot_options;
1375 #if RUN_IN_SUBTHREAD
1376                 mono_runtime_exec_managed_code (domain, main_thread_handler, &main_args);
1377 #else
1378                 main_thread_handler (&main_args);
1379                 mono_thread_manage ();
1380 #endif
1381                 mini_cleanup (domain);
1382
1383                 /* Look up return value from System.Environment.ExitCode */
1384                 i = mono_environment_exitcode_get ();
1385                 return i;
1386         } else if (action == DO_COMPILE) {
1387                 compile_all_methods (assembly, mini_verbose, opt);
1388                 mini_cleanup (domain);
1389                 return 0;
1390         } else if (action == DO_DEBUGGER) {
1391 #ifdef MONO_DEBUGGER_SUPPORTED
1392                 const char *error;
1393
1394                 error = mono_check_corlib_version ();
1395                 if (error) {
1396                         fprintf (stderr, "Corlib not in sync with this runtime: %s\n", error);
1397                         fprintf (stderr, "Download a newer corlib or a newer runtime at http://www.go-mono.com/daily.\n");
1398                         exit (1);
1399                 }
1400
1401                 mono_debugger_main (domain, assembly, argc - i, argv + i);
1402                 mini_cleanup (domain);
1403                 return 0;
1404 #else
1405                 return 1;
1406 #endif
1407         }
1408         desc = mono_method_desc_new (mname, 0);
1409         if (!desc) {
1410                 g_print ("Invalid method name %s\n", mname);
1411                 mini_cleanup (domain);
1412                 return 3;
1413         }
1414         method = mono_method_desc_search_in_image (desc, mono_assembly_get_image (assembly));
1415         if (!method) {
1416                 g_print ("Cannot find method %s\n", mname);
1417                 mini_cleanup (domain);
1418                 return 3;
1419         }
1420
1421         if (action == DO_DRAW) {
1422                 int part = 0;
1423
1424                 switch (mono_graph_options) {
1425                 case MONO_GRAPH_DTREE:
1426                         part = 1;
1427                         opt |= MONO_OPT_LOOP;
1428                         break;
1429                 case MONO_GRAPH_CFG_CODE:
1430                         part = 1;
1431                         break;
1432                 case MONO_GRAPH_CFG_SSA:
1433                         part = 2;
1434                         break;
1435                 case MONO_GRAPH_CFG_OPTCODE:
1436                         part = 3;
1437                         break;
1438                 default:
1439                         break;
1440                 }
1441
1442                 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
1443                         (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
1444                         MonoMethod *nm;
1445                         nm = mono_marshal_get_native_wrapper (method);
1446                         cfg = mini_method_compile (nm, opt, mono_get_root_domain (), FALSE, FALSE, part);
1447                 }
1448                 else
1449                         cfg = mini_method_compile (method, opt, mono_get_root_domain (), FALSE, FALSE, part);
1450                 if ((mono_graph_options & MONO_GRAPH_CFG_SSA) && !(cfg->comp_done & MONO_COMP_SSA)) {
1451                         g_warning ("no SSA info available (use -O=deadce)");
1452                         return 1;
1453                 }
1454                 mono_draw_graph (cfg, mono_graph_options);
1455                 mono_destroy_compile (cfg);
1456
1457         } else if (action == DO_BENCH) {
1458                 if (mini_stats_fd) {
1459                         const char *n;
1460                         double no_opt_time = 0.0;
1461                         GTimer *timer = g_timer_new ();
1462                         fprintf (mini_stats_fd, "$stattitle = \'Compilations times for %s\';\n", 
1463                                  mono_method_full_name (method, TRUE));
1464                         fprintf (mini_stats_fd, "@data = (\n");
1465                         fprintf (mini_stats_fd, "[");
1466                         for (i = 0; i < G_N_ELEMENTS (opt_sets); i++) {
1467                                 opt = opt_sets [i];
1468                                 n = opt_descr (opt);
1469                                 if (!n [0])
1470                                         n = "none";
1471                                 fprintf (mini_stats_fd, "\"%s\",", n);
1472                         }
1473                         fprintf (mini_stats_fd, "],\n[");
1474
1475                         for (i = 0; i < G_N_ELEMENTS (opt_sets); i++) {
1476                                 int j;
1477                                 double elapsed;
1478                                 opt = opt_sets [i];
1479                                 g_timer_start (timer);
1480                                 for (j = 0; j < count; ++j) {
1481                                         cfg = mini_method_compile (method, opt, mono_get_root_domain (), FALSE, FALSE, 0);
1482                                         mono_destroy_compile (cfg);
1483                                 }
1484                                 g_timer_stop (timer);
1485                                 elapsed = g_timer_elapsed (timer, NULL);
1486                                 if (!opt)
1487                                         no_opt_time = elapsed;
1488                                 fprintf (mini_stats_fd, "%f, ", elapsed);
1489                         }
1490                         fprintf (mini_stats_fd, "]");
1491                         if (no_opt_time > 0.0) {
1492                                 fprintf (mini_stats_fd, ", \n[");
1493                                 for (i = 0; i < G_N_ELEMENTS (opt_sets); i++) 
1494                                         fprintf (mini_stats_fd, "%f,", no_opt_time);
1495                                 fprintf (mini_stats_fd, "]");
1496                         }
1497                         fprintf (mini_stats_fd, ");\n");
1498                 } else {
1499                         for (i = 0; i < count; ++i) {
1500                                 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
1501                                         (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
1502                                         method = mono_marshal_get_native_wrapper (method);
1503
1504                                 cfg = mini_method_compile (method, opt, mono_get_root_domain (), FALSE, FALSE, 0);
1505                                 mono_destroy_compile (cfg);
1506                         }
1507                 }
1508         } else {
1509                 cfg = mini_method_compile (method, opt, mono_get_root_domain (), FALSE, FALSE, 0);
1510                 mono_destroy_compile (cfg);
1511         }
1512
1513         mini_cleanup (domain);
1514         return 0;
1515 }
1516
1517 MonoDomain * 
1518 mono_jit_init (const char *file)
1519 {
1520         return mini_init (file, NULL);
1521 }
1522
1523 /**
1524  * mono_jit_init_version:
1525  * @file: the initial assembly to load
1526  * @runtime_version: the version of the runtime to load
1527  *
1528  * Use this version when you want to force a particular runtime
1529  * version to be used.  By default Mono will pick the runtime that is
1530  * referenced by the initial assembly (specified in @file), this
1531  * routine allows programmers to specify the actual runtime to be used
1532  * as the initial runtime is inherited by all future assemblies loaded
1533  * (since Mono does not support having more than one mscorlib runtime
1534  * loaded at once).
1535  *
1536  * The @runtime_version can be one of these strings: "v1.1.4322" for
1537  * the 1.1 runtime or "v2.0.50727"  for the 2.0 runtime. 
1538  *
1539  * Returns: the MonoDomain representing the domain where the assembly
1540  * was loaded.
1541  */
1542 MonoDomain * 
1543 mono_jit_init_version (const char *file, const char *runtime_version)
1544 {
1545         return mini_init (file, runtime_version);
1546 }
1547
1548 void        
1549 mono_jit_cleanup (MonoDomain *domain)
1550 {
1551         mini_cleanup (domain);
1552 }