In dis:
[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 #ifdef HAVE_UNISTD_H
15 #include <unistd.h>
16 #endif
17
18 #include <mono/metadata/assembly.h>
19 #include <mono/metadata/loader.h>
20 #include <mono/metadata/cil-coff.h>
21 #include <mono/metadata/tabledefs.h>
22 #include <mono/metadata/class.h>
23 #include <mono/metadata/object.h>
24 #include <mono/metadata/exception.h>
25 #include <mono/metadata/opcodes.h>
26 #include <mono/metadata/mono-endian.h>
27 #include <mono/metadata/tokentype.h>
28 #include <mono/metadata/tabledefs.h>
29 #include <mono/metadata/threads.h>
30 #include <mono/metadata/marshal.h>
31 #include <mono/metadata/socket-io.h>
32 #include <mono/metadata/appdomain.h>
33 #include <mono/metadata/debug-helpers.h>
34 #include <mono/io-layer/io-layer.h>
35 #include "mono/metadata/profiler.h"
36 #include <mono/metadata/profiler-private.h>
37 #include <mono/metadata/mono-config.h>
38 #include <mono/metadata/environment.h>
39 #include <mono/metadata/verify.h>
40 #include <mono/metadata/mono-debug.h>
41 #include <mono/metadata/security-manager.h>
42 #include <mono/os/gc_wrapper.h>
43 #include "mono/utils/mono-counters.h"
44
45 #include "mini.h"
46 #include "jit.h"
47 #include <string.h>
48 #include <ctype.h>
49 #include "inssel.h"
50 #include <locale.h>
51 #include "version.h"
52
53 static FILE *mini_stats_fd = NULL;
54
55 static void mini_usage (void);
56
57 /* This turns off command line globbing under win32 */
58 #ifdef PLATFORM_WIN32
59 int _CRT_glob = 0;
60 #endif
61
62 typedef void (*OptFunc) (const char *p);
63
64 #undef OPTFLAG
65 #ifdef HAVE_ARRAY_ELEM_INIT
66 #define MSGSTRFIELD(line) MSGSTRFIELD1(line)
67 #define MSGSTRFIELD1(line) str##line
68
69 static const struct msgstr_t {
70 #define OPTFLAG(id,shift,name,desc) char MSGSTRFIELD(__LINE__) [sizeof (name) + sizeof (desc)];
71 #include "optflags-def.h"
72 #undef OPTFLAG
73 } opstr = {
74 #define OPTFLAG(id,shift,name,desc) name "\0" desc,
75 #include "optflags-def.h"
76 #undef OPTFLAG
77 };
78 static const gint16 opt_names [] = {
79 #define OPTFLAG(id,shift,name,desc) [(shift)] = offsetof (struct msgstr_t, MSGSTRFIELD(__LINE__)),
80 #include "optflags-def.h"
81 #undef OPTFLAG
82 };
83
84 #define optflag_get_name(id) ((const char*)&opstr + opt_names [(id)])
85 #define optflag_get_desc(id) (optflag_get_name(id) + 1 + strlen (optflag_get_name(id)))
86
87 #else /* !HAVE_ARRAY_ELEM_INIT */
88 typedef struct {
89         const char* name;
90         const char* desc;
91 } OptName;
92
93 #define OPTFLAG(id,shift,name,desc) {name,desc},
94 static const OptName 
95 opt_names [] = {
96 #include "optflags-def.h"
97         {NULL, NULL}
98 };
99 #define optflag_get_name(id) (opt_names [(id)].name)
100 #define optflag_get_desc(id) (opt_names [(id)].desc)
101
102 #endif
103
104 static const OptFunc
105 opt_funcs [sizeof (int) * 8] = {
106         NULL
107 };
108
109 #define DEFAULT_OPTIMIZATIONS ( \
110         MONO_OPT_PEEPHOLE |     \
111         MONO_OPT_CFOLD |        \
112         MONO_OPT_INLINE |       \
113         MONO_OPT_CONSPROP |     \
114         MONO_OPT_COPYPROP |     \
115         MONO_OPT_TREEPROP |     \
116         MONO_OPT_DEADCE |       \
117         MONO_OPT_BRANCH |       \
118         MONO_OPT_LINEARS |      \
119         MONO_OPT_INTRINS |  \
120         MONO_OPT_LOOP |  \
121         MONO_OPT_EXCEPTION |  \
122         MONO_OPT_AOT)
123
124 #define EXCLUDED_FROM_ALL (MONO_OPT_SHARED | MONO_OPT_PRECOMP)
125
126 static guint32
127 parse_optimizations (const char* p)
128 {
129         /* the default value */
130         guint32 opt = DEFAULT_OPTIMIZATIONS;
131         guint32 exclude = 0;
132         const char *n;
133         int i, invert, len;
134
135         /* call out to cpu detection code here that sets the defaults ... */
136         opt |= mono_arch_cpu_optimizazions (&exclude);
137         opt &= ~exclude;
138         if (!p)
139                 return opt;
140
141         while (*p) {
142                 if (*p == '-') {
143                         p++;
144                         invert = TRUE;
145                 } else {
146                         invert = FALSE;
147                 }
148                 for (i = 0; i < G_N_ELEMENTS (opt_names) && optflag_get_name (i); ++i) {
149                         n = optflag_get_name (i);
150                         len = strlen (n);
151                         if (strncmp (p, n, len) == 0) {
152                                 if (invert)
153                                         opt &= ~ (1 << i);
154                                 else
155                                         opt |= 1 << i;
156                                 p += len;
157                                 if (*p == ',') {
158                                         p++;
159                                         break;
160                                 } else if (*p == '=') {
161                                         p++;
162                                         if (opt_funcs [i])
163                                                 opt_funcs [i] (p);
164                                         while (*p && *p++ != ',');
165                                         break;
166                                 }
167                                 /* error out */
168                                 break;
169                         }
170                 }
171                 if (i == G_N_ELEMENTS (opt_names) || !optflag_get_name (i)) {
172                         if (strncmp (p, "all", 3) == 0) {
173                                 if (invert)
174                                         opt = 0;
175                                 else
176                                         opt = ~(EXCLUDED_FROM_ALL | exclude);
177                                 p += 3;
178                                 if (*p == ',')
179                                         p++;
180                         } else {
181                                 fprintf (stderr, "Invalid optimization name `%s'\n", p);
182                                 exit (1);
183                         }
184                 }
185         }
186         return opt;
187 }
188
189 typedef struct {
190         const char name [6];
191         const char desc [18];
192         MonoGraphOptions value;
193 } GraphName;
194
195 static const GraphName 
196 graph_names [] = {
197         {"cfg",      "Control Flow",                            MONO_GRAPH_CFG},
198         {"dtree",    "Dominator Tree",                          MONO_GRAPH_DTREE},
199         {"code",     "CFG showing code",                        MONO_GRAPH_CFG_CODE},
200         {"ssa",      "CFG after SSA",                           MONO_GRAPH_CFG_SSA},
201         {"optc",     "CFG after IR opts",                       MONO_GRAPH_CFG_OPTCODE}
202 };
203
204 static MonoGraphOptions
205 mono_parse_graph_options (const char* p)
206 {
207         const char *n;
208         int i, len;
209
210         for (i = 0; i < G_N_ELEMENTS (graph_names); ++i) {
211                 n = graph_names [i].name;
212                 len = strlen (n);
213                 if (strncmp (p, n, len) == 0)
214                         return graph_names [i].value;
215         }
216
217         fprintf (stderr, "Invalid graph name provided: %s\n", p);
218         exit (1);
219 }
220
221 int
222 mono_parse_default_optimizations (const char* p)
223 {
224         guint32 opt;
225
226         opt = parse_optimizations (p);
227         return opt;
228 }
229
230 static char*
231 opt_descr (guint32 flags) {
232         GString *str = g_string_new ("");
233         int i, need_comma;
234
235         need_comma = 0;
236         for (i = 0; i < G_N_ELEMENTS (opt_names); ++i) {
237                 if (flags & (1 << i)) {
238                         if (need_comma)
239                                 g_string_append_c (str, ',');
240                         g_string_append (str, optflag_get_name (i));
241                         need_comma = 1;
242                 }
243         }
244         return g_string_free (str, FALSE);
245 }
246
247 static const guint32
248 opt_sets [] = {
249        0,
250        MONO_OPT_PEEPHOLE,
251        MONO_OPT_BRANCH,
252        MONO_OPT_CFOLD,
253        MONO_OPT_FCMOV,
254        MONO_OPT_BRANCH | MONO_OPT_PEEPHOLE | MONO_OPT_INTRINS,
255        MONO_OPT_BRANCH | MONO_OPT_PEEPHOLE | MONO_OPT_LINEARS,
256        MONO_OPT_BRANCH | MONO_OPT_PEEPHOLE | MONO_OPT_LINEARS | MONO_OPT_COPYPROP,
257        MONO_OPT_BRANCH | MONO_OPT_PEEPHOLE | MONO_OPT_LINEARS | MONO_OPT_CFOLD,
258        MONO_OPT_BRANCH | MONO_OPT_PEEPHOLE | MONO_OPT_LINEARS | MONO_OPT_COPYPROP | MONO_OPT_CONSPROP | MONO_OPT_DEADCE,
259        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,
260        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,
261        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,
262        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,
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 | MONO_OPT_EXCEPTION | MONO_OPT_ABCREM | MONO_OPT_SSAPRE,
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_ABCREM,
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_TREEPROP,
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_SSAPRE,
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_ABCREM | MONO_OPT_SHARED
268 };
269
270 typedef int (*TestMethod) (void);
271
272 #if 0
273 static void
274 domain_dump_native_code (MonoDomain *domain) {
275         // need to poke into the domain, move to metadata/domain.c
276         // need to empty jit_info_table and code_mp
277 }
278 #endif
279
280 static int
281 mini_regression (MonoImage *image, int verbose, int *total_run) {
282         guint32 i, opt, opt_flags;
283         MonoMethod *method;
284         MonoCompile *cfg;
285         char *n;
286         int result, expected, failed, cfailed, run, code_size, total;
287         TestMethod func;
288         GTimer *timer = g_timer_new ();
289
290         if (mini_stats_fd) {
291                 fprintf (mini_stats_fd, "$stattitle = \'Mono Benchmark Results (various optimizations)\';\n");
292
293                 fprintf (mini_stats_fd, "$graph->set_legend(qw(");
294                 for (opt = 0; opt < G_N_ELEMENTS (opt_sets); opt++) {
295                         opt_flags = opt_sets [opt];
296                         n = opt_descr (opt_flags);
297                         if (!n [0])
298                                 n = (char *)"none";
299                         if (opt)
300                                 fprintf (mini_stats_fd, " ");
301                         fprintf (mini_stats_fd, "%s", n);
302                 
303
304                 }
305                 fprintf (mini_stats_fd, "));\n");
306
307                 fprintf (mini_stats_fd, "@data = (\n");
308                 fprintf (mini_stats_fd, "[");
309         }
310
311         /* load the metadata */
312         for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
313                 method = mono_get_method (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL);
314                 mono_class_init (method->klass);
315
316                 if (!strncmp (method->name, "test_", 5) && mini_stats_fd) {
317                         fprintf (mini_stats_fd, "\"%s\",", method->name);
318                 }
319         }
320         if (mini_stats_fd)
321                 fprintf (mini_stats_fd, "],\n");
322
323
324         total = 0;
325         *total_run = 0;
326         for (opt = 0; opt < G_N_ELEMENTS (opt_sets); ++opt) {
327                 double elapsed, comp_time, start_time;
328
329                 opt_flags = opt_sets [opt];
330                 mono_set_defaults (verbose, opt_flags);
331                 n = opt_descr (opt_flags);
332                 g_print ("Test run: image=%s, opts=%s\n", mono_image_get_filename (image), n);
333                 g_free (n);
334                 cfailed = failed = run = code_size = 0;
335                 comp_time = elapsed = 0.0;
336
337                 /* fixme: ugly hack - delete all previously compiled methods */
338                 g_hash_table_destroy (mono_domain_get ()->jit_trampoline_hash);
339                 mono_domain_get ()->jit_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
340                 mono_internal_hash_table_destroy (&(mono_domain_get ()->jit_code_hash));
341                 mono_jit_code_hash_init (&(mono_domain_get ()->jit_code_hash));
342
343                 g_timer_start (timer);
344                 if (mini_stats_fd)
345                         fprintf (mini_stats_fd, "[");
346                 for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
347                         method = mono_get_method (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL);
348                         if (strncmp (method->name, "test_", 5) == 0) {
349                                 expected = atoi (method->name + 5);
350                                 run++;
351                                 start_time = g_timer_elapsed (timer, NULL);
352                                 comp_time -= start_time; 
353                                 cfg = mini_method_compile (method, opt_flags, mono_get_root_domain (), TRUE, FALSE, 0);
354                                 comp_time += g_timer_elapsed (timer, NULL);
355                                 if (cfg->exception_type == MONO_EXCEPTION_NONE) {
356                                         if (verbose >= 2)
357                                                 g_print ("Running '%s' ...\n", method->name);
358 #ifdef MONO_USE_AOT_COMPILER
359                                         if ((func = mono_aot_get_method (mono_get_root_domain (), method)))
360                                                 ;
361                                         else
362 #endif
363                                                 func = (TestMethod)(gpointer)cfg->native_code;
364                                         func = (TestMethod)mono_create_ftnptr (mono_get_root_domain (), func);
365                                         result = func ();
366                                         if (result != expected) {
367                                                 failed++;
368                                                 g_print ("Test '%s' failed result (got %d, expected %d).\n", method->name, result, expected);
369                                         }
370                                         code_size += cfg->code_len;
371                                         mono_destroy_compile (cfg);
372
373                                 } else {
374                                         cfailed++;
375                                         if (verbose)
376                                                 g_print ("Test '%s' failed compilation.\n", method->name);
377                                 }
378                                 if (mini_stats_fd)
379                                         fprintf (mini_stats_fd, "%f, ", 
380                                                  g_timer_elapsed (timer, NULL) - start_time);
381                         }
382                 }
383                 if (mini_stats_fd)
384                         fprintf (mini_stats_fd, "],\n");
385                 g_timer_stop (timer);
386                 elapsed = g_timer_elapsed (timer, NULL);
387                 if (failed > 0 || cfailed > 0){
388                         g_print ("Results: total tests: %d, failed: %d, cfailed: %d (pass: %.2f%%)\n", 
389                                  run, failed, cfailed, 100.0*(run-failed-cfailed)/run);
390                 } else {
391                         g_print ("Results: total tests: %d, all pass \n",  run);
392                 }
393                 
394                 g_print ("Elapsed time: %f secs (%f, %f), Code size: %d\n\n", elapsed, 
395                          elapsed - comp_time, comp_time, code_size);
396                 total += failed + cfailed;
397                 *total_run += run;
398         }
399
400         if (mini_stats_fd) {
401                 fprintf (mini_stats_fd, ");\n");
402                 fflush (mini_stats_fd);
403         }
404
405         g_timer_destroy (timer);
406         return total;
407 }
408
409 static int
410 mini_regression_list (int verbose, int count, char *images [])
411 {
412         int i, total, total_run, run;
413         MonoAssembly *ass;
414         
415         total_run =  total = 0;
416         for (i = 0; i < count; ++i) {
417                 ass = mono_assembly_open (images [i], NULL);
418                 if (!ass) {
419                         g_warning ("failed to load assembly: %s", images [i]);
420                         continue;
421                 }
422                 total += mini_regression (mono_assembly_get_image (ass), verbose, &run);
423                 total_run += run;
424         }
425         if (total > 0){
426                 g_print ("Overall results: tests: %d, failed: %d, opt combinations: %d (pass: %.2f%%)\n", 
427                          total_run, total, (int)G_N_ELEMENTS (opt_sets), 100.0*(total_run-total)/total_run);
428         } else {
429                 g_print ("Overall results: tests: %d, 100%% pass, opt combinations: %d\n", 
430                          total_run, (int)G_N_ELEMENTS (opt_sets));
431         }
432         
433         return total;
434 }
435
436 enum {
437         DO_BENCH,
438         DO_REGRESSION,
439         DO_COMPILE,
440         DO_EXEC,
441         DO_DRAW,
442         DO_DEBUGGER
443 };
444
445 typedef struct CompileAllThreadArgs {
446         MonoAssembly *ass;
447         int verbose;
448         guint32 opts;
449 } CompileAllThreadArgs;
450
451 static void
452 compile_all_methods_thread_main (CompileAllThreadArgs *args)
453 {
454         MonoAssembly *ass = args->ass;
455         int verbose = args->verbose;
456         MonoImage *image = mono_assembly_get_image (ass);
457         MonoMethod *method;
458         MonoCompile *cfg;
459         int i, count = 0;
460
461         for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
462                 guint32 token = MONO_TOKEN_METHOD_DEF | (i + 1);
463                 MonoMethodSignature *sig;
464
465                 if (mono_metadata_has_generic_params (image, token))
466                         continue;
467
468                 method = mono_get_method (image, token, NULL);
469                 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
470                     (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
471                     (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
472                     (method->flags & METHOD_ATTRIBUTE_ABSTRACT))
473                         continue;
474
475                 if (method->klass->generic_container)
476                         continue;
477                 sig = mono_method_signature (method);
478                 if (sig->has_type_parameters)
479                         continue;
480
481                 count++;
482                 if (verbose) {
483                         char * desc = mono_method_full_name (method, TRUE);
484                         g_print ("Compiling %d %s\n", count, desc);
485                         g_free (desc);
486                 }
487                 cfg = mini_method_compile (method, args->opts, mono_get_root_domain (), FALSE, FALSE, 0);
488                 mono_destroy_compile (cfg);
489         }
490
491 }
492
493 static void
494 compile_all_methods (MonoAssembly *ass, int verbose, guint32 opts)
495 {
496         CompileAllThreadArgs args;
497
498         args.ass = ass;
499         args.verbose = verbose;
500         args.opts = opts;
501
502         /* 
503          * Need to create a mono thread since compilation might trigger
504          * running of managed code.
505          */
506         mono_thread_create (mono_domain_get (), compile_all_methods_thread_main, &args);
507
508         mono_thread_manage ();
509 }
510
511 /**
512  * mono_jit_exec:
513  * @assembly: reference to an assembly
514  * @argc: argument count
515  * @argv: argument vector
516  *
517  * Start execution of a program.
518  */
519 int 
520 mono_jit_exec (MonoDomain *domain, MonoAssembly *assembly, int argc, char *argv[])
521 {
522         MonoImage *image = mono_assembly_get_image (assembly);
523         MonoMethod *method;
524         guint32 entry = mono_image_get_entry_point (image);
525
526         if (!entry) {
527                 g_print ("Assembly '%s' doesn't have an entry point.\n", mono_image_get_filename (image));
528                 /* FIXME: remove this silly requirement. */
529                 mono_environment_exitcode_set (1);
530                 return 1;
531         }
532
533         method = mono_get_method (image, entry, NULL);
534         if (method == NULL){
535                 g_print ("The entry point method could not be loaded\n");
536                 mono_environment_exitcode_set (1);
537                 return 1;
538         }
539         
540         return mono_runtime_run_main (method, argc, argv, NULL);
541 }
542
543 typedef struct 
544 {
545         MonoDomain *domain;
546         const char *file;
547         int argc;
548         char **argv;
549         guint32 opts;
550         char *aot_options;
551 } MainThreadArgs;
552
553 static void main_thread_handler (gpointer user_data)
554 {
555         MainThreadArgs *main_args = user_data;
556         MonoAssembly *assembly;
557
558         assembly = mono_domain_assembly_open (main_args->domain, main_args->file);
559         if (!assembly){
560                 fprintf (stderr, "Can not open image %s\n", main_args->file);
561                 exit (1);
562         }
563
564         if (mono_compile_aot) {
565                 int res = mono_compile_assembly (assembly, main_args->opts, main_args->aot_options);
566                 printf ("AOT RESULT %d\n", res);
567         } else {
568                 /* 
569                  * This must be done in a thread managed by mono since it can invoke
570                  * managed code.
571                  */
572                 if (main_args->opts & MONO_OPT_PRECOMP)
573                         mono_precompile_assemblies ();
574
575                 mono_jit_exec (main_args->domain, assembly, main_args->argc, main_args->argv);
576         }
577 }
578
579 static void
580 mini_usage_jitdeveloper (void)
581 {
582         int i;
583         
584         fprintf (stdout,
585                  "Runtime and JIT debugging options:\n"
586                  "    --breakonex            Inserts a breakpoint on exceptions\n"
587                  "    --break METHOD         Inserts a breakpoint at METHOD entry\n"
588                  "    --compile METHOD       Just compile METHOD in assembly\n"
589                  "    --compile-all          Compiles all the methods in the assembly\n"
590                  "    --ncompile N           Number of times to compile METHOD (default: 1)\n"
591                  "    --print-vtable         Print the vtable of all used classes\n"
592                  "    --regression           Runs the regression test contained in the assembly\n"
593                  "    --statfile FILE        Sets the stat file to FILE\n"
594                  "    --stats                Print statistics about the JIT operations\n"
595                  "    --wapi=hps|semdel      IO-layer maintenance\n"
596                  "\n"
597                  "Other options:\n" 
598                  "    --graph[=TYPE] METHOD  Draws a graph of the specified method:\n");
599         
600         for (i = 0; i < G_N_ELEMENTS (graph_names); ++i) {
601                 fprintf (stdout, "                           %-10s %s\n", graph_names [i].name, graph_names [i].desc);
602         }
603 }
604
605 static void
606 mini_usage_list_opt (void)
607 {
608         int i;
609         
610         for (i = 0; i < G_N_ELEMENTS (opt_names); ++i)
611                 fprintf (stdout, "                           %-10s %s\n", optflag_get_name (i), optflag_get_desc (i));
612 }
613
614 static void
615 mini_usage (void)
616 {
617         fprintf (stdout,
618                 "Usage is: mono [options] program [program-options]\n"
619                 "\n"
620                 "Development:\n"
621                 "    --aot                  Compiles the assembly to native code\n"
622                 "    --debug                Enable debugging support\n"
623                 "    --profile[=profiler]   Runs in profiling mode with the specified profiler module\n"
624                 "    --trace[=EXPR]         Enable tracing, use --help-trace for details\n"
625                 "    --help-devel           Shows more options available to developers\n"
626                 "\n"
627                 "Runtime:\n"
628                 "    --config FILE          Loads FILE as the Mono config\n"
629                 "    --verbose, -v          Increases the verbosity level\n"
630                 "    --help, -h             Show usage information\n"
631                 "    --version, -V          Show version information\n"
632                 "    --runtime=VERSION      Use the VERSION runtime, instead of autodetecting\n"
633                 "    --optimize=OPT         Turns on or off a specific optimization\n"
634                 "                           Use --list-opt to get a list of optimizations\n"
635                 "    --security             Turns on the security manager (unsupported, default is off)\n");
636 }
637
638 static void
639 mini_trace_usage (void)
640 {
641         fprintf (stdout,
642                  "Tracing options:\n"
643                  "   --trace[=EXPR]        Trace every call, optional EXPR controls the scope\n"
644                  "\n"
645                  "EXPR is composed of:\n"
646                  "    all                  All assemblies\n"
647                  "    none                 No assemblies\n"
648                  "    program              Entry point assembly\n"
649                  "    assembly             Specifies an assembly\n"
650                  "    M:Type:Method        Specifies a method\n"
651                  "    N:Namespace          Specifies a namespace\n"
652                  "    T:Type               Specifies a type\n"
653                  "    +EXPR                Includes expression\n"
654                  "    -EXPR                Excludes expression\n"
655                  "    disabled             Don't print any output until toggled via SIGUSR2\n");
656 }
657
658 static const char info[] =
659 #ifdef HAVE_KW_THREAD
660         "\tTLS:           __thread\n"
661 #else
662         "\tTLS:           normal\n"
663 #endif /* HAVE_KW_THREAD */
664         "\tGC:            " USED_GC_NAME "\n"
665 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
666     "\tSIGSEGV:       altstack\n"
667 #else
668     "\tSIGSEGV:       normal\n"
669 #endif
670         "\tArchitecture:  " ARCHITECTURE "\n"
671         "\tDisabled:      " DISABLED_FEATURES "\n"
672         "";
673
674 int
675 mono_main (int argc, char* argv[])
676 {
677         MainThreadArgs main_args;
678         MonoAssembly *assembly;
679         MonoMethodDesc *desc;
680         MonoMethod *method;
681         MonoCompile *cfg;
682         MonoDomain *domain;
683         const char* aname, *mname = NULL;
684         char *config_file = NULL;
685         int i, count = 1;
686         int enable_debugging = FALSE;
687         guint32 opt, action = DO_EXEC;
688         MonoGraphOptions mono_graph_options = 0;
689         int mini_verbose = 0;
690         gboolean enable_profile = FALSE;
691         char *trace_options = NULL;
692         char *profile_options = NULL;
693         char *aot_options = NULL;
694         char *forced_version = NULL;
695
696         setlocale (LC_ALL, "");
697
698         if (!g_thread_supported ())
699                 g_thread_init (NULL);
700
701         if (mono_running_on_valgrind () && getenv ("MONO_VALGRIND_LEAK_CHECK")) {
702                 GMemVTable mem_vtable;
703
704                 /* 
705                  * Instruct glib to use the system allocation functions so valgrind
706                  * can track the memory allocated by the g_... functions.
707                  */
708                 memset (&mem_vtable, 0, sizeof (mem_vtable));
709                 mem_vtable.malloc = malloc;
710                 mem_vtable.realloc = realloc;
711                 mem_vtable.free = free;
712                 mem_vtable.calloc = calloc;
713
714                 g_mem_set_vtable (&mem_vtable);
715         }
716
717         g_log_set_always_fatal (G_LOG_LEVEL_ERROR);
718         g_log_set_fatal_mask (G_LOG_DOMAIN, G_LOG_LEVEL_ERROR);
719
720         opt = parse_optimizations (NULL);
721
722         for (i = 1; i < argc; ++i) {
723                 if (argv [i] [0] != '-')
724                         break;
725                 if (strcmp (argv [i], "--regression") == 0) {
726                         action = DO_REGRESSION;
727                 } else if (strcmp (argv [i], "--verbose") == 0 || strcmp (argv [i], "-v") == 0) {
728                         mini_verbose++;
729                 } else if (strcmp (argv [i], "--version") == 0 || strcmp (argv [i], "-V") == 0) {
730                         g_print ("Mono JIT compiler version %s (%s)\nCopyright (C) 2002-2007 Novell, Inc and Contributors. www.mono-project.com\n", VERSION, FULL_VERSION);
731                         g_print (info);
732                         if (mini_verbose) {
733                                 const char *cerror;
734                                 const char *clibpath;
735                                 mono_init ("mono");
736                                 cerror = mono_check_corlib_version ();
737                                 clibpath = mono_defaults.corlib? mono_image_get_filename (mono_defaults.corlib): "unknown";
738                                 if (cerror) {
739                                         g_print ("The currently installed mscorlib doesn't match this runtime version.\n");
740                                         g_print ("The error is: %s\n", cerror);
741                                         g_print ("mscorlib.dll loaded at: %s\n", clibpath);
742                                         return 1;
743                                 }
744                         }
745                         return 0;
746                 } else if (strcmp (argv [i], "--help") == 0 || strcmp (argv [i], "-h") == 0) {
747                         mini_usage ();
748                         return 0;
749                 } else if (strcmp (argv [i], "--help-trace") == 0){
750                         mini_trace_usage ();
751                         return 0;
752                 } else if (strcmp (argv [i], "--help-devel") == 0){
753                         mini_usage_jitdeveloper ();
754                         return 0;
755                 } else if (strcmp (argv [i], "--list-opt") == 0){
756                         mini_usage_list_opt ();
757                         return 0;
758                 } else if (strncmp (argv [i], "--statfile", 10) == 0) {
759                         if (i + 1 >= argc){
760                                 fprintf (stderr, "error: --statfile requires a filename argument\n");
761                                 return 1;
762                         }
763                         mini_stats_fd = fopen (argv [++i], "w+");
764                 } else if (strncmp (argv [i], "--optimize=", 11) == 0) {
765                         opt = parse_optimizations (argv [i] + 11);
766                 } else if (strncmp (argv [i], "-O=", 3) == 0) {
767                         opt = parse_optimizations (argv [i] + 3);
768                 } else if (strcmp (argv [i], "--config") == 0) {
769                         if (i +1 >= argc){
770                                 fprintf (stderr, "error: --config requires a filename argument\n");
771                                 return 1;
772                         }
773                         config_file = argv [++i];
774                 } else if (strcmp (argv [i], "--ncompile") == 0) {
775                         if (i + 1 >= argc){
776                                 fprintf (stderr, "error: --ncompile requires an argument\n");
777                                 return 1;
778                         }
779                         count = atoi (argv [++i]);
780                         action = DO_BENCH;
781                 } else if (strcmp (argv [i], "--trace") == 0) {
782                         trace_options = (char*)"";
783                 } else if (strncmp (argv [i], "--trace=", 8) == 0) {
784                         trace_options = &argv [i][8];
785                 } else if (strcmp (argv [i], "--breakonex") == 0) {
786                         mono_break_on_exc = TRUE;
787                 } else if (strcmp (argv [i], "--break") == 0) {
788                         if (i+1 >= argc){
789                                 fprintf (stderr, "Missing method name in --break command line option\n");
790                                 return 1;
791                         }
792                         
793                         if (!mono_debugger_insert_breakpoint (argv [++i], FALSE))
794                                 fprintf (stderr, "Error: invalid method name '%s'\n", argv [i]);
795                 } else if (strcmp (argv [i], "--print-vtable") == 0) {
796                         mono_print_vtable = TRUE;
797                 } else if (strcmp (argv [i], "--stats") == 0) {
798                         mono_counters_enable (-1);
799                         mono_stats.enabled = TRUE;
800                         mono_jit_stats.enabled = TRUE;
801 #ifndef DISABLE_AOT
802                 } else if (strcmp (argv [i], "--aot") == 0) {
803                         mono_compile_aot = TRUE;
804                 } else if (strncmp (argv [i], "--aot=", 6) == 0) {
805                         mono_compile_aot = TRUE;
806                         aot_options = &argv [i][6];
807 #endif
808                 } else if (strcmp (argv [i], "--compile-all") == 0) {
809                         action = DO_COMPILE;
810                 } else if (strncmp (argv [i], "--runtime=", 10) == 0) {
811                         forced_version = &argv [i][10];
812                 } else if (strcmp (argv [i], "--profile") == 0) {
813                         enable_profile = TRUE;
814                         profile_options = NULL;
815                 } else if (strncmp (argv [i], "--profile=", 10) == 0) {
816                         enable_profile = TRUE;
817                         profile_options = argv [i] + 10;
818                 } else if (strcmp (argv [i], "--compile") == 0) {
819                         if (i + 1 >= argc){
820                                 fprintf (stderr, "error: --compile option requires a method name argument\n");
821                                 return 1;
822                         }
823                         
824                         mname = argv [++i];
825                         action = DO_BENCH;
826                 } else if (strncmp (argv [i], "--graph=", 8) == 0) {
827                         if (i + 1 >= argc){
828                                 fprintf (stderr, "error: --graph option requires a method name argument\n");
829                                 return 1;
830                         }
831                         
832                         mono_graph_options = mono_parse_graph_options (argv [i] + 8);
833                         mname = argv [++i];
834                         action = DO_DRAW;
835                 } else if (strcmp (argv [i], "--graph") == 0) {
836                         if (i + 1 >= argc){
837                                 fprintf (stderr, "error: --graph option requires a method name argument\n");
838                                 return 1;
839                         }
840                         
841                         mname = argv [++i];
842                         mono_graph_options = MONO_GRAPH_CFG;
843                         action = DO_DRAW;
844                 } else if (strcmp (argv [i], "--debug") == 0) {
845                         enable_debugging = TRUE;
846                 } else if (strcmp (argv [i], "--security") == 0) {
847                         mono_use_security_manager = TRUE;
848                         mono_activate_security_manager ();
849                 } else if (strcmp (argv [i], "--desktop") == 0) {
850 #if defined (HAVE_BOEHM_GC)
851                         GC_dont_expand = 1;
852 #endif
853                         /* Put desktop-specific optimizations here */
854                 } else if (strcmp (argv [i], "--server") == 0){
855                         /* Put server-specific optimizations here */
856                 } else if (strcmp (argv [i], "--inside-mdb") == 0) {
857                         action = DO_DEBUGGER;
858                 } else if (strncmp (argv [i], "--wapi=", 7) == 0) {
859                         if (strcmp (argv [i] + 7, "hps") == 0) {
860                                 return mini_wapi_hps (argc - i, argv + i);
861                         } else if (strcmp (argv [i] + 7, "semdel") == 0) {
862                                 return mini_wapi_semdel (argc - i, argv + i);
863                         } else if (strcmp (argv [i] + 7, "seminfo") == 0) {
864                                 return mini_wapi_seminfo (argc - i, argv + i);
865                         } else {
866                                 fprintf (stderr, "Invalid --wapi suboption: '%s'\n", argv [i]);
867                                 return 1;
868                         }
869                 } else {
870                         fprintf (stderr, "Unknown command line option: '%s'\n", argv [i]);
871                         return 1;
872                 }
873         }
874
875         if (!argv [i]) {
876                 mini_usage ();
877                 return 1;
878         }
879
880         if ((action == DO_EXEC) && g_getenv ("MONO_INSIDE_MDB"))
881                 action = DO_DEBUGGER;
882
883         if (mono_compile_aot || action == DO_EXEC || action == DO_DEBUGGER) {
884                 g_set_prgname (argv[i]);
885         }
886
887         if (enable_profile) {
888                 /* Needed because of TLS accesses in mono_profiler_load () */
889                 MONO_GC_PRE_INIT ();
890                 mono_profiler_load (profile_options);
891         }
892
893         if (trace_options != NULL){
894                 /* 
895                  * Need to call this before mini_init () so we can trace methods 
896                  * compiled there too.
897                  */
898                 mono_jit_trace_calls = mono_trace_parse_options (trace_options);
899                 if (mono_jit_trace_calls == NULL)
900                         exit (1);
901         }
902
903         if (action == DO_DEBUGGER) {
904                 opt |= MONO_OPT_SHARED;
905                 opt &= ~MONO_OPT_INLINE;
906                 opt &= ~MONO_OPT_COPYPROP;
907                 opt &= ~MONO_OPT_CONSPROP;
908                 enable_debugging = TRUE;
909
910 #ifdef MONO_DEBUGGER_SUPPORTED
911                 mono_debug_init (MONO_DEBUG_FORMAT_DEBUGGER);
912                 mono_debugger_init ();
913 #else
914                 g_print ("The Mono Debugger is not supported on this platform.\n");
915                 return 1;
916 #endif
917         }
918
919         mono_set_defaults (mini_verbose, opt);
920         domain = mini_init (argv [i], forced_version);
921         
922         switch (action) {
923         case DO_REGRESSION:
924                 if (mini_regression_list (mini_verbose, argc -i, argv + i)) {
925                         g_print ("Regression ERRORS!\n");
926                         mini_cleanup (domain);
927                         return 1;
928                 }
929                 mini_cleanup (domain);
930                 return 0;
931         case DO_BENCH:
932                 if (argc - i != 1 || mname == NULL) {
933                         g_print ("Usage: mini --ncompile num --compile method assembly\n");
934                         mini_cleanup (domain);
935                         return 1;
936                 }
937                 aname = argv [i];
938                 break;
939         case DO_COMPILE:
940                 if (argc - i != 1) {
941                         mini_usage ();
942                         mini_cleanup (domain);
943                         return 1;
944                 }
945                 aname = argv [i];
946                 break;
947         case DO_DRAW:
948                 if (argc - i != 1 || mname == NULL) {
949                         mini_usage ();
950                         mini_cleanup (domain);
951                         return 1;
952                 }
953                 aname = argv [i];
954                 break;
955         default:
956                 if (argc - i < 1) {
957                         mini_usage ();
958                         mini_cleanup (domain);
959                         return 1;
960                 }
961                 aname = argv [i];
962                 break;
963         }
964
965         if (action == DO_DEBUGGER)
966                 mono_debug_init_1 (domain);
967         else if (enable_debugging) {
968                 mono_debug_init (MONO_DEBUG_FORMAT_MONO);
969                 mono_debug_init_1 (domain);
970         }
971
972         /* Parse gac loading options before loading assemblies. */
973         if (mono_compile_aot || action == DO_EXEC || action == DO_DEBUGGER) {
974                 mono_config_parse (config_file);
975         }
976
977         assembly = mono_assembly_open (aname, NULL);
978         if (!assembly) {
979                 fprintf (stderr, "Cannot open assembly %s.\n", aname);
980                 mini_cleanup (domain);
981                 return 2;
982         }
983
984         if (trace_options != NULL)
985                 mono_trace_set_assembly (assembly);
986
987         if (enable_debugging)
988                 mono_debug_init_2 (assembly);
989
990         if (mono_compile_aot || action == DO_EXEC) {
991                 const char *error;
992
993                 //mono_set_rootdir ();
994
995                 error = mono_check_corlib_version ();
996                 if (error) {
997                         fprintf (stderr, "Corlib not in sync with this runtime: %s\n", error);
998                         fprintf (stderr, "Loaded from: %s\n",
999                                 mono_defaults.corlib? mono_image_get_filename (mono_defaults.corlib): "unknown");
1000                         fprintf (stderr, "Download a newer corlib or a newer runtime at http://www.go-mono.com/daily.\n");
1001                         exit (1);
1002                 }
1003
1004 #ifdef PLATFORM_WIN32
1005                 /* Detach console when executing IMAGE_SUBSYSTEM_WINDOWS_GUI on win32 */
1006                 if (!enable_debugging && !mono_compile_aot && ((MonoCLIImageInfo*)(mono_assembly_get_image (assembly)->image_info))->cli_header.nt.pe_subsys_required == IMAGE_SUBSYSTEM_WINDOWS_GUI)
1007                         FreeConsole ();
1008 #endif
1009
1010                 main_args.domain = domain;
1011                 main_args.file = aname;         
1012                 main_args.argc = argc - i;
1013                 main_args.argv = argv + i;
1014                 main_args.opts = opt;
1015                 main_args.aot_options = aot_options;
1016 #if RUN_IN_SUBTHREAD
1017                 mono_runtime_exec_managed_code (domain, main_thread_handler, &main_args);
1018 #else
1019                 main_thread_handler (&main_args);
1020                 mono_thread_manage ();
1021 #endif
1022                 mini_cleanup (domain);
1023
1024                 /* Look up return value from System.Environment.ExitCode */
1025                 i = mono_environment_exitcode_get ();
1026                 return i;
1027         } else if (action == DO_COMPILE) {
1028                 compile_all_methods (assembly, mini_verbose, opt);
1029                 mini_cleanup (domain);
1030                 return 0;
1031         } else if (action == DO_DEBUGGER) {
1032 #ifdef MONO_DEBUGGER_SUPPORTED
1033                 const char *error;
1034
1035                 error = mono_check_corlib_version ();
1036                 if (error) {
1037                         fprintf (stderr, "Corlib not in sync with this runtime: %s\n", error);
1038                         fprintf (stderr, "Download a newer corlib or a newer runtime at http://www.go-mono.com/daily.\n");
1039                         exit (1);
1040                 }
1041
1042                 mono_debugger_main (domain, assembly, argc - i, argv + i);
1043                 mini_cleanup (domain);
1044                 return 0;
1045 #else
1046                 return 1;
1047 #endif
1048         }
1049         desc = mono_method_desc_new (mname, 0);
1050         if (!desc) {
1051                 g_print ("Invalid method name %s\n", mname);
1052                 mini_cleanup (domain);
1053                 return 3;
1054         }
1055         method = mono_method_desc_search_in_image (desc, mono_assembly_get_image (assembly));
1056         if (!method) {
1057                 g_print ("Cannot find method %s\n", mname);
1058                 mini_cleanup (domain);
1059                 return 3;
1060         }
1061
1062         if (action == DO_DRAW) {
1063                 int part = 0;
1064
1065                 switch (mono_graph_options) {
1066                 case MONO_GRAPH_DTREE:
1067                         part = 1;
1068                         opt |= MONO_OPT_LOOP;
1069                         break;
1070                 case MONO_GRAPH_CFG_CODE:
1071                         part = 1;
1072                         break;
1073                 case MONO_GRAPH_CFG_SSA:
1074                         part = 2;
1075                         break;
1076                 case MONO_GRAPH_CFG_OPTCODE:
1077                         part = 3;
1078                         break;
1079                 default:
1080                         break;
1081                 }
1082
1083                 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
1084                         (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
1085                         MonoMethod *nm;
1086                         nm = mono_marshal_get_native_wrapper (method);
1087                         cfg = mini_method_compile (nm, opt, mono_get_root_domain (), FALSE, FALSE, part);
1088                 }
1089                 else
1090                         cfg = mini_method_compile (method, opt, mono_get_root_domain (), FALSE, FALSE, part);
1091                 if ((mono_graph_options & MONO_GRAPH_CFG_SSA) && !(cfg->comp_done & MONO_COMP_SSA)) {
1092                         g_warning ("no SSA info available (use -O=deadce)");
1093                         return 1;
1094                 }
1095                 mono_draw_graph (cfg, mono_graph_options);
1096                 mono_destroy_compile (cfg);
1097
1098         } else if (action == DO_BENCH) {
1099                 if (mini_stats_fd) {
1100                         const char *n;
1101                         double no_opt_time = 0.0;
1102                         GTimer *timer = g_timer_new ();
1103                         fprintf (mini_stats_fd, "$stattitle = \'Compilations times for %s\';\n", 
1104                                  mono_method_full_name (method, TRUE));
1105                         fprintf (mini_stats_fd, "@data = (\n");
1106                         fprintf (mini_stats_fd, "[");
1107                         for (i = 0; i < G_N_ELEMENTS (opt_sets); i++) {
1108                                 opt = opt_sets [i];
1109                                 n = opt_descr (opt);
1110                                 if (!n [0])
1111                                         n = "none";
1112                                 fprintf (mini_stats_fd, "\"%s\",", n);
1113                         }
1114                         fprintf (mini_stats_fd, "],\n[");
1115
1116                         for (i = 0; i < G_N_ELEMENTS (opt_sets); i++) {
1117                                 int j;
1118                                 double elapsed;
1119                                 opt = opt_sets [i];
1120                                 g_timer_start (timer);
1121                                 for (j = 0; j < count; ++j) {
1122                                         cfg = mini_method_compile (method, opt, mono_get_root_domain (), FALSE, FALSE, 0);
1123                                         mono_destroy_compile (cfg);
1124                                 }
1125                                 g_timer_stop (timer);
1126                                 elapsed = g_timer_elapsed (timer, NULL);
1127                                 if (!opt)
1128                                         no_opt_time = elapsed;
1129                                 fprintf (mini_stats_fd, "%f, ", elapsed);
1130                         }
1131                         fprintf (mini_stats_fd, "]");
1132                         if (no_opt_time > 0.0) {
1133                                 fprintf (mini_stats_fd, ", \n[");
1134                                 for (i = 0; i < G_N_ELEMENTS (opt_sets); i++) 
1135                                         fprintf (mini_stats_fd, "%f,", no_opt_time);
1136                                 fprintf (mini_stats_fd, "]");
1137                         }
1138                         fprintf (mini_stats_fd, ");\n");
1139                 } else {
1140                         for (i = 0; i < count; ++i) {
1141                                 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
1142                                         (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
1143                                         method = mono_marshal_get_native_wrapper (method);
1144
1145                                 cfg = mini_method_compile (method, opt, mono_get_root_domain (), FALSE, FALSE, 0);
1146                                 mono_destroy_compile (cfg);
1147                         }
1148                 }
1149         } else {
1150                 cfg = mini_method_compile (method, opt, mono_get_root_domain (), FALSE, FALSE, 0);
1151                 mono_destroy_compile (cfg);
1152         }
1153
1154         mini_cleanup (domain);
1155         return 0;
1156 }
1157
1158 MonoDomain * 
1159 mono_jit_init (const char *file)
1160 {
1161         return mini_init (file, NULL);
1162 }
1163
1164 MonoDomain * 
1165 mono_jit_init_version (const char *file, const char *runtime_version)
1166 {
1167         return mini_init (file, runtime_version);
1168 }
1169
1170 void        
1171 mono_jit_cleanup (MonoDomain *domain)
1172 {
1173         mini_cleanup (domain);
1174 }