2003-12-18 Zoltan Varga <vargaz@freemail.hu>
[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 Ximian, Inc.
9  */
10
11 #include <config.h>
12 #include <signal.h>
13 #include <unistd.h>
14
15 #include <mono/metadata/assembly.h>
16 #include <mono/metadata/loader.h>
17 #include <mono/metadata/cil-coff.h>
18 #include <mono/metadata/tabledefs.h>
19 #include <mono/metadata/class.h>
20 #include <mono/metadata/object.h>
21 #include <mono/metadata/exception.h>
22 #include <mono/metadata/opcodes.h>
23 #include <mono/metadata/mono-endian.h>
24 #include <mono/metadata/tokentype.h>
25 #include <mono/metadata/tabledefs.h>
26 #include <mono/metadata/threads.h>
27 #include <mono/metadata/marshal.h>
28 #include <mono/metadata/socket-io.h>
29 #include <mono/metadata/appdomain.h>
30 #include <mono/metadata/debug-helpers.h>
31 #include <mono/io-layer/io-layer.h>
32 #include "mono/metadata/profiler.h"
33 #include <mono/metadata/profiler-private.h>
34 #include <mono/metadata/mono-config.h>
35 #include <mono/metadata/environment.h>
36 #include <mono/metadata/verify.h>
37 #include <mono/metadata/mono-debug.h>
38 #include <mono/metadata/mono-debug-debugger.h>
39
40 #include "mini.h"
41 #include "jit.h"
42 #include <string.h>
43 #include <ctype.h>
44 #include "inssel.h"
45 #include <locale.h>
46
47 static FILE *mini_stats_fd = NULL;
48
49 static void mini_usage (void);
50
51 typedef void (*OptFunc) (const char *p);
52
53 /* keep in sync with enum in mini.h */
54 typedef struct {
55         const char* name;
56         const char* desc;
57         const OptFunc func;
58 } OptName;
59
60 static const OptName 
61 opt_names [] = {
62         {"peephole", "Peephole postpass"},
63         {"branch",   "Branch optimizations"},
64         {"inline",   "Inline method calls"},
65         {"cfold",    "Constant folding"},
66         {"consprop", "Constant propagation"},
67         {"copyprop", "Copy propagation"},
68         {"deadce",   "Dead code elimination"},
69         {"linears",  "Linear scan global reg allocation"},
70         {"cmov",     "Conditional moves"},
71         {"shared",   "Emit per-domain code"},
72         {"sched",    "Instruction scheduling"},
73         {"intrins",  "Intrinsic method implementations"},
74         {"tailc",    "Tail recursion and tail calls"},
75         {"loop",     "Loop related optimizations"},
76         {"fcmov",    "Fast x86 FP compares"},
77         {"leaf",     "Leaf procedures optimizations"},
78         {"aot",      "Usage of Ahead Of Time compiled code"},
79         {"precomp",  "Precompile all methods before executing Main"}
80 };
81
82 #define DEFAULT_OPTIMIZATIONS ( \
83         MONO_OPT_PEEPHOLE |     \
84         MONO_OPT_CFOLD |        \
85         MONO_OPT_BRANCH |       \
86         MONO_OPT_LINEARS |      \
87         MONO_OPT_INTRINS |  \
88     MONO_OPT_AOT)
89
90 static guint32
91 parse_optimizations (const char* p)
92 {
93         /* the default value */
94         guint32 opt = DEFAULT_OPTIMIZATIONS;
95         guint32 exclude = 0;
96         const char *n;
97         int i, invert, len;
98
99         /* call out to cpu detection code here that sets the defaults ... */
100         opt |= mono_arch_cpu_optimizazions (&exclude);
101         opt &= ~exclude;
102         if (!p)
103                 return opt;
104
105         while (*p) {
106                 if (*p == '-') {
107                         p++;
108                         invert = TRUE;
109                 } else {
110                         invert = FALSE;
111                 }
112                 for (i = 0; i < G_N_ELEMENTS (opt_names); ++i) {
113                         n = opt_names [i].name;
114                         len = strlen (n);
115                         if (strncmp (p, n, len) == 0) {
116                                 if (invert)
117                                         opt &= ~ (1 << i);
118                                 else
119                                         opt |= 1 << i;
120                                 p += len;
121                                 if (*p == ',') {
122                                         p++;
123                                         break;
124                                 } else if (*p == '=') {
125                                         p++;
126                                         if (opt_names [i].func)
127                                                 opt_names [i].func (p);
128                                         while (*p && *p++ != ',');
129                                         break;
130                                 }
131                                 /* error out */
132                                 break;
133                         }
134                 }
135                 if (i == G_N_ELEMENTS (opt_names)) {
136                         if (strncmp (p, "all", 3) == 0) {
137                                 if (invert)
138                                         opt = 0;
139                                 else
140                                         opt = ~(MONO_OPT_SHARED | MONO_OPT_PRECOMP | exclude);
141                                 p += 3;
142                                 if (*p == ',')
143                                         p++;
144                         } else {
145                                 fprintf (stderr, "Invalid optimization name `%s'\n", p);
146                                 exit (1);
147                         }
148                 }
149         }
150         return opt;
151 }
152
153 typedef struct {
154         const char* name;
155         const char* desc;
156         MonoGraphOptions value;
157 } GraphName;
158
159 static const GraphName 
160 graph_names [] = {
161         {"cfg",      "Control Flow Graph (CFG)" ,               MONO_GRAPH_CFG},
162         {"dtree",    "Dominator Tree",                          MONO_GRAPH_DTREE},
163         {"code",     "CFG showing code",                        MONO_GRAPH_CFG_CODE},
164         {"ssa",      "CFG showing code after SSA translation",  MONO_GRAPH_CFG_SSA},
165         {"optcode",  "CFG showing code after IR optimizations", MONO_GRAPH_CFG_OPTCODE}
166 };
167
168 static MonoGraphOptions
169 mono_parse_graph_options (const char* p)
170 {
171         const char *n;
172         int i, len;
173
174         for (i = 0; i < G_N_ELEMENTS (graph_names); ++i) {
175                 n = graph_names [i].name;
176                 len = strlen (n);
177                 if (strncmp (p, n, len) == 0)
178                         return graph_names [i].value;
179         }
180
181         fprintf (stderr, "Invalid graph name provided: %s\n", p);
182         exit (1);
183 }
184
185 int
186 mono_parse_default_optimizations (const char* p)
187 {
188         guint32 opt;
189
190         opt = parse_optimizations (p);
191         return opt;
192 }
193
194 static char*
195 opt_descr (guint32 flags) {
196         GString *str = g_string_new ("");
197         int i, need_comma;
198
199         need_comma = 0;
200         for (i = 0; i < G_N_ELEMENTS (opt_names); ++i) {
201                 if (flags & (1 << i)) {
202                         if (need_comma)
203                                 g_string_append_c (str, ',');
204                         g_string_append (str, opt_names [i].name);
205                         need_comma = 1;
206                 }
207         }
208         return g_string_free (str, FALSE);
209 }
210
211 static const guint32
212 opt_sets [] = {
213        0,
214        MONO_OPT_PEEPHOLE,
215        MONO_OPT_BRANCH,
216        MONO_OPT_CFOLD,
217        MONO_OPT_FCMOV,
218        MONO_OPT_BRANCH | MONO_OPT_PEEPHOLE | MONO_OPT_INTRINS,
219        MONO_OPT_BRANCH | MONO_OPT_PEEPHOLE | MONO_OPT_LINEARS,
220        MONO_OPT_BRANCH | MONO_OPT_PEEPHOLE | MONO_OPT_LINEARS | MONO_OPT_COPYPROP,
221        MONO_OPT_BRANCH | MONO_OPT_PEEPHOLE | MONO_OPT_LINEARS | MONO_OPT_CFOLD,
222        MONO_OPT_BRANCH | MONO_OPT_PEEPHOLE | MONO_OPT_LINEARS | MONO_OPT_COPYPROP | MONO_OPT_CONSPROP | MONO_OPT_DEADCE,
223        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
224 };
225
226 typedef int (*TestMethod) (void);
227
228 #if 0
229 static void
230 domain_dump_native_code (MonoDomain *domain) {
231         // need to poke into the domain, move to metadata/domain.c
232         // need to empty jit_info_table and code_mp
233 }
234 #endif
235
236 static int
237 mini_regression (MonoImage *image, int verbose, int *total_run) {
238         guint32 i, opt, opt_flags;
239         MonoMethod *method;
240         MonoCompile *cfg;
241         char *n;
242         int result, expected, failed, cfailed, run, code_size, total;
243         TestMethod func;
244         GTimer *timer = g_timer_new ();
245
246         if (mini_stats_fd) {
247                 fprintf (mini_stats_fd, "$stattitle = \'Mono Benchmark Results (various optimizations)\';\n");
248
249                 fprintf (mini_stats_fd, "$graph->set_legend(qw(");
250                 for (opt = 0; opt < G_N_ELEMENTS (opt_sets); opt++) {
251                         opt_flags = opt_sets [opt];
252                         n = opt_descr (opt_flags);
253                         if (!n [0])
254                                 n = (char *)"none";
255                         if (opt)
256                                 fprintf (mini_stats_fd, " ");
257                         fprintf (mini_stats_fd, "%s", n);
258                 
259
260                 }
261                 fprintf (mini_stats_fd, "));\n");
262
263                 fprintf (mini_stats_fd, "@data = (\n");
264                 fprintf (mini_stats_fd, "[");
265         }
266
267         /* load the metadata */
268         for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
269                 method = mono_get_method (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL);
270                 mono_class_init (method->klass);
271
272                 if (!strncmp (method->name, "test_", 5) && mini_stats_fd) {
273                         fprintf (mini_stats_fd, "\"%s\",", method->name);
274                 }
275         }
276         if (mini_stats_fd)
277                 fprintf (mini_stats_fd, "],\n");
278
279
280         total = 0;
281         *total_run = 0;
282         for (opt = 0; opt < G_N_ELEMENTS (opt_sets); ++opt) {
283                 double elapsed, comp_time, start_time;
284                 MonoJitInfo *jinfo;
285
286                 opt_flags = opt_sets [opt];
287                 mono_set_defaults (verbose, opt_flags);
288                 n = opt_descr (opt_flags);
289                 g_print ("Test run: image=%s, opts=%s\n", image->name, n);
290                 g_free (n);
291                 cfailed = failed = run = code_size = 0;
292                 comp_time = elapsed = 0.0;
293
294                 /* fixme: ugly hack - delete all previously compiled methods */
295                 for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
296                         method = mono_get_method (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL);
297                         method->info = NULL;
298                 }
299
300                 g_timer_start (timer);
301                 if (mini_stats_fd)
302                         fprintf (mini_stats_fd, "[");
303                 for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
304                         method = mono_get_method (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL);
305                         if (strncmp (method->name, "test_", 5) == 0) {
306                                 expected = atoi (method->name + 5);
307                                 run++;
308                                 start_time = g_timer_elapsed (timer, NULL);
309                                 comp_time -= start_time; 
310                                 cfg = mini_method_compile (method, opt_flags, mono_root_domain, TRUE, 0);
311                                 comp_time += g_timer_elapsed (timer, NULL);
312                                 if (cfg) {
313                                         if (verbose >= 2)
314                                                 g_print ("Running '%s' ...\n", method->name);
315 #ifdef MONO_USE_AOT_COMPILER
316                                         if ((jinfo = mono_aot_get_method (mono_root_domain, method)))
317                                                 func = jinfo->code_start;
318                                         else
319 #endif
320                                                 func = (TestMethod)cfg->native_code;
321                                         result = func ();
322                                         if (result != expected) {
323                                                 failed++;
324                                                 if (verbose)
325                                                         g_print ("Test '%s' failed result (got %d, expected %d).\n", method->name, result, expected);
326                                         }
327                                         code_size += cfg->code_len;
328                                         mono_destroy_compile (cfg);
329
330                                 } else {
331                                         cfailed++;
332                                         if (verbose)
333                                                 g_print ("Test '%s' failed compilation.\n", method->name);
334                                 }
335                                 if (mini_stats_fd)
336                                         fprintf (mini_stats_fd, "%f, ", 
337                                                  g_timer_elapsed (timer, NULL) - start_time);
338                         }
339                 }
340                 if (mini_stats_fd)
341                         fprintf (mini_stats_fd, "],\n");
342                 g_timer_stop (timer);
343                 elapsed = g_timer_elapsed (timer, NULL);
344                 g_print ("Results: total tests: %d, failed: %d, cfailed: %d (pass: %.2f%%)\n", 
345                         run, failed, cfailed, 100.0*(run-failed-cfailed)/run);
346                 g_print ("Elapsed time: %f secs (%f, %f), Code size: %d\n\n", elapsed, 
347                          elapsed - comp_time, comp_time, code_size);
348                 total += failed + cfailed;
349                 *total_run += run;
350         }
351
352         if (mini_stats_fd) {
353                 fprintf (mini_stats_fd, ");\n");
354                 fflush (mini_stats_fd);
355         }
356
357         g_timer_destroy (timer);
358         return total;
359 }
360
361 static int
362 mini_regression_list (int verbose, int count, char *images [])
363 {
364         int i, total, total_run, run;
365         MonoAssembly *ass;
366         
367         total_run =  total = 0;
368         for (i = 0; i < count; ++i) {
369                 ass = mono_assembly_open (images [i], NULL);
370                 if (!ass) {
371                         g_warning ("failed to load assembly: %s", images [i]);
372                         continue;
373                 }
374                 total += mini_regression (ass->image, verbose, &run);
375                 total_run += run;
376                 mono_assembly_close (ass);
377         }
378         g_print ("Overall results: tests: %d, failed: %d, opt combinations: %d (pass: %.2f%%)\n", 
379                 total_run, total, G_N_ELEMENTS (opt_sets), 100.0*(total_run-total)/total_run);
380         return total;
381 }
382
383 enum {
384         DO_BENCH,
385         DO_REGRESSION,
386         DO_COMPILE,
387         DO_EXEC,
388         DO_DRAW,
389 };
390
391 typedef struct CompileAllThreadArgs {
392         MonoAssembly *ass;
393         int verbose;
394 } CompileAllThreadArgs;
395
396 static void
397 compile_all_methods_thread_main (CompileAllThreadArgs *args)
398 {
399         MonoAssembly *ass = args->ass;
400         int verbose = args->verbose;
401         MonoImage *image = ass->image;
402         MonoMethod *method;
403         int i, count = 0;
404
405         for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
406                 method = mono_get_method (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL);
407                 if (method->flags & METHOD_ATTRIBUTE_ABSTRACT)
408                         continue;
409                 if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)
410                         continue;
411
412                 count++;
413                 if (verbose) {
414                         char * desc = mono_method_full_name (method, TRUE);
415                         g_print ("Compiling %d %s\n", count, desc);
416                         g_free (desc);
417                 }
418                 mono_compile_method (method);
419         }
420
421 }
422
423 static void
424 compile_all_methods (MonoAssembly *ass, int verbose)
425 {
426         CompileAllThreadArgs args;
427
428         args.ass = ass;
429         args.verbose = verbose;
430
431         /* 
432          * Need to create a mono thread since compilation might trigger
433          * running of managed code.
434          */
435         mono_thread_create (mono_domain_get (), compile_all_methods_thread_main, &args);
436
437         mono_thread_manage ();
438 }
439
440 /**
441  * mono_jit_exec:
442  * @assembly: reference to an assembly
443  * @argc: argument count
444  * @argv: argument vector
445  *
446  * Start execution of a program.
447  */
448 int 
449 mono_jit_exec (MonoDomain *domain, MonoAssembly *assembly, int argc, char *argv[])
450 {
451         MonoImage *image = assembly->image;
452         MonoMethod *method;
453         guint32 entry = mono_image_get_entry_point (image);
454
455         if (!entry) {
456                 g_print ("Assembly '%s' doesn't have an entry point.\n", image->name);
457                 /* FIXME: remove this silly requirement. */
458                 mono_environment_exitcode_set (1);
459                 return 1;
460         }
461
462         method = mono_get_method (image, entry, NULL);
463
464         return mono_runtime_run_main (method, argc, argv, NULL);
465 }
466
467 typedef struct 
468 {
469         MonoDomain *domain;
470         const char *file;
471         int argc;
472         char **argv;
473         guint32 opts;
474 } MainThreadArgs;
475
476 static void main_thread_handler (gpointer user_data)
477 {
478         MainThreadArgs *main_args = user_data;
479         MonoAssembly *assembly;
480
481         assembly = mono_domain_assembly_open (main_args->domain, main_args->file);
482         if (!assembly){
483                 fprintf (stderr, "Can not open image %s\n", main_args->file);
484                 exit (1);
485         }
486
487         if (mono_compile_aot) {
488                 int res = mono_compile_assembly (assembly, main_args->opts);
489                 printf ("AOT RESULT %d\n", res);
490         } else {
491                 /* 
492                  * This must be done in a thread managed by mono since it can invoke
493                  * managed code.
494                  */
495                 if (main_args->opts & MONO_OPT_PRECOMP)
496                         mono_precompile_assemblies ();
497
498                 mono_jit_exec (main_args->domain, assembly, main_args->argc, main_args->argv);
499         }
500 }
501
502 static void
503 mini_usage (void)
504 {
505         int i;
506
507         fprintf (stderr,
508                 "Usage is: mono [options] assembly\n\n"
509                 "Runtime and JIT debugging:\n"
510                 "    --compile METHOD       Just compile METHOD in assembly\n"
511                 "    --ncompile N           Number of times to compile METHOD (default: 1)\n"
512                 "    --regression           Runs the regression test contained in the assembly\n"
513                 "    --print-vtable         Print the vtable of all used classes\n"
514                 "    --trace[=EXPR]         Enable tracing, use --help-trace for details\n"
515                 "    --compile-all          Compiles all the methods in the assembly\n"
516                 "    --breakonex            Inserts a breakpoint on exceptions\n"
517                 "    --break METHOD         Inserts a breakpoint at METHOD entry\n"
518                 "    --debug                Enable debugging support\n"
519             "    --stats                Print statistics about the JIT operations\n"
520                 "\n"
521                 "Development:\n"
522                 "    --statfile FILE        Sets the stat file to FILE\n"
523                 "    --aot                  Compiles the assembly to native code\n"
524                 "    --profile[=profiler]   Runs in profiling mode with the specified profiler module\n"
525                 "    --graph[=TYPE] METHOD  Draws a graph of the specified method:\n");
526         
527         for (i = 0; i < G_N_ELEMENTS (graph_names); ++i) {
528                 fprintf (stderr, "                           %-10s %s\n", graph_names [i].name, graph_names [i].desc);
529         }
530
531         fprintf (stderr,
532                 "\n"
533                 "Runtime:\n"
534                 "    --config FILE          Loads FILE as the Mono config\n"
535                 "    --verbose, -v          Increases the verbosity level\n"
536                 "    --help, -h             Show usage information\n"
537                 "    --version, -V          Show version information\n"
538                 "    --optimize=OPT         Turns on a specific optimization:\n");
539
540         for (i = 0; i < G_N_ELEMENTS (opt_names); ++i)
541                 fprintf (stderr, "                           %-10s %s\n", opt_names [i].name, opt_names [i].desc);
542 }
543
544 static void
545 mini_trace_usage (void)
546 {
547         fprintf (stderr,
548                  "Tracing options:\n"
549                  "   --trace[=EXPR]        Trace every call, optional EXPR controls the scope\n"
550                  "\n"
551                  "EXPR is composed of:\n"
552                  "    all                  All assemblies\n"
553                  "    none                 No assemblies\n"
554                  "    program              Entry point assembly\n"
555                  "    assembly             Specifies an assembly\n"
556                  "    M:Type:Method        Specifies a method\n"
557                  "    N:Namespace          Specifies a namespace\n"
558                  "    T:Type               Specifies a type\n"
559                  "    +EXPR                Includes expression\n"
560                  "    -EXPR                Excludes expression\n");
561 }
562
563 int
564 mono_main (int argc, char* argv[])
565 {
566         MainThreadArgs main_args;
567         MonoAssembly *assembly;
568         MonoMethodDesc *desc;
569         MonoMethod *method;
570         MonoCompile *cfg;
571         MonoDomain *domain;
572         const char* aname, *mname = NULL;
573         char *config_file = NULL;
574         int i, count = 1;
575         int enable_debugging = FALSE;
576         guint32 opt, action = DO_EXEC;
577         MonoGraphOptions mono_graph_options = 0;
578         int mini_verbose = 0;
579         char *trace_options = NULL;
580
581         setlocale (LC_ALL, "");
582         g_log_set_always_fatal (G_LOG_LEVEL_ERROR);
583         g_log_set_fatal_mask (G_LOG_DOMAIN, G_LOG_LEVEL_ERROR);
584         
585         opt = parse_optimizations (NULL);
586
587         for (i = 1; i < argc; ++i) {
588                 if (argv [i] [0] != '-')
589                         break;
590                 if (strcmp (argv [i], "--regression") == 0) {
591                         action = DO_REGRESSION;
592                 } else if (strcmp (argv [i], "--verbose") == 0 || strcmp (argv [i], "-v") == 0) {
593                         mini_verbose++;
594                 } else if (strcmp (argv [i], "--version") == 0 || strcmp (argv [i], "-V") == 0) {
595                         g_print ("Mono JIT compiler version %s, (C) 2002, 2003 Ximian, Inc.\n", VERSION);
596                         return 0;
597                 } else if (strcmp (argv [i], "--help") == 0 || strcmp (argv [i], "-h") == 0) {
598                         mini_usage ();
599                         return 0;
600                 } else if (strcmp (argv [i], "--help-trace") == 0){
601                         mini_trace_usage ();
602                         return 0;
603                 } else if (strncmp (argv [i], "--statfile", 10) == 0) {
604                         mini_stats_fd = fopen (argv [++i], "w+");
605                 } else if (strncmp (argv [i], "--optimize=", 11) == 0) {
606                         opt = parse_optimizations (argv [i] + 11);
607                 } else if (strncmp (argv [i], "-O=", 3) == 0) {
608                         opt = parse_optimizations (argv [i] + 3);
609                 } else if (strcmp (argv [i], "--config") == 0) {
610                         config_file = argv [++i];
611                 } else if (strcmp (argv [i], "--ncompile") == 0) {
612                         count = atoi (argv [++i]);
613                         action = DO_BENCH;
614                 } else if (strcmp (argv [i], "--trace") == 0) {
615                         trace_options = "";
616                 } else if (strncmp (argv [i], "--trace=", 8) == 0) {
617                         trace_options = &argv [i][8];
618                 } else if (strcmp (argv [i], "--breakonex") == 0) {
619                         mono_break_on_exc = TRUE;
620                 } else if (strcmp (argv [i], "--break") == 0) {
621                         if (!mono_debugger_insert_breakpoint (argv [++i], FALSE))
622                                 g_error ("Invalid method name '%s'", argv [i]);
623                 } else if (strcmp (argv [i], "--print-vtable") == 0) {
624                         mono_print_vtable = TRUE;
625                 } else if (strcmp (argv [i], "--stats") == 0) {
626                         mono_jit_stats.enabled = TRUE;
627                 } else if (strcmp (argv [i], "--aot") == 0) {
628                         mono_compile_aot = TRUE;
629                 } else if (strcmp (argv [i], "--compile-all") == 0) {
630                         action = DO_COMPILE;
631                 } else if (strcmp (argv [i], "--profile") == 0) {
632                         mono_profiler_load (NULL);
633                 } else if (strncmp (argv [i], "--profile=", 10) == 0) {
634                         mono_profiler_load (argv [i] + 10);
635                 } else if (strcmp (argv [i], "--compile") == 0) {
636                         mname = argv [++i];
637                         action = DO_BENCH;
638                 } else if (strncmp (argv [i], "--graph=", 8) == 0) {
639                         mono_graph_options = mono_parse_graph_options (argv [i] + 8);
640                         mname = argv [++i];
641                         action = DO_DRAW;
642                 } else if (strcmp (argv [i], "--graph") == 0) {
643                         mname = argv [++i];
644                         mono_graph_options = MONO_GRAPH_CFG;
645                         action = DO_DRAW;
646                 } else if (strcmp (argv [i], "--debug") == 0) {
647                         enable_debugging = TRUE;
648                 } else {
649                         fprintf (stderr, "Unknown command line option: '%s'\n", argv [i]);
650                         return 1;
651                 }
652         }
653
654         if (!argv [i]) {
655                 mini_usage ();
656                 return 1;
657         }
658
659         if (mono_compile_aot || action == DO_EXEC) {
660                 g_set_prgname (argv[i]);
661         }
662
663         mono_set_defaults (mini_verbose, opt);
664         domain = mini_init (argv [i]);
665         
666         switch (action) {
667         case DO_REGRESSION:
668                 if (mini_regression_list (mini_verbose, argc -i, argv + i)) {
669                         g_print ("Regression ERRORS!\n");
670                         mini_cleanup (domain);
671                         return 1;
672                 }
673                 mini_cleanup (domain);
674                 return 0;
675         case DO_BENCH:
676                 if (argc - i != 1 || mname == NULL) {
677                         g_print ("Usage: mini --ncompile num --compile method assembly\n");
678                         mini_cleanup (domain);
679                         return 1;
680                 }
681                 aname = argv [i];
682                 break;
683         case DO_COMPILE:
684                 if (argc - i != 1) {
685                         mini_usage ();
686                         mini_cleanup (domain);
687                         return 1;
688                 }
689                 aname = argv [i];
690                 break;
691         case DO_DRAW:
692                 if (argc - i != 1 || mname == NULL) {
693                         mini_usage ();
694                         mini_cleanup (domain);
695                         return 1;
696                 }
697                 aname = argv [i];
698                 break;
699         default:
700                 if (argc - i < 1) {
701                         mini_usage ();
702                         mini_cleanup (domain);
703                         return 1;
704                 }
705                 aname = argv [i];
706                 break;
707         }
708
709         if (enable_debugging)
710                 mono_debug_init (domain, MONO_DEBUG_FORMAT_MONO);
711
712         assembly = mono_assembly_open (aname, NULL);
713         if (!assembly) {
714                 fprintf (stderr, "cannot open assembly %s\n", aname);
715                 mini_cleanup (domain);
716                 return 2;
717         }
718
719         if (trace_options != NULL){
720                 mono_jit_trace_calls = mono_trace_parse_options (assembly, trace_options);
721                 if (mono_jit_trace_calls == NULL)
722                         exit (1);
723         }
724
725         if (enable_debugging)
726                 mono_debug_init_2 (assembly);
727
728         if (mono_compile_aot || action == DO_EXEC) {
729                 guint32 error;
730
731                 mono_config_parse (config_file);
732                 //mono_set_rootdir ();
733
734                 error = mono_check_corlib_version ();
735                 if (error) {
736                         fprintf (stderr, "Corlib not in sync with this runtime: %s\n", error);
737                         fprintf (stderr, "Download a newer corlib or a newer runtime at http://go-mono/daily.\n");
738                         exit (1);
739                 }
740
741                 main_args.domain = domain;
742                 main_args.file = aname;         
743                 main_args.argc = argc - i;
744                 main_args.argv = argv + i;
745                 main_args.opts = opt;
746              
747                 mono_runtime_exec_managed_code (domain, main_thread_handler, &main_args);
748                 mini_cleanup (domain);
749
750                 /* Look up return value from System.Environment.ExitCode */
751                 i = mono_environment_exitcode_get ();
752                 return i;
753         } else if (action == DO_COMPILE) {
754                 compile_all_methods (assembly, mini_verbose);
755                 mini_cleanup (domain);
756                 return 0;
757         }
758         desc = mono_method_desc_new (mname, 0);
759         if (!desc) {
760                 g_print ("Invalid method name %s\n", mname);
761                 mini_cleanup (domain);
762                 return 3;
763         }
764         method = mono_method_desc_search_in_image (desc, assembly->image);
765         if (!method) {
766                 g_print ("Cannot find method %s\n", mname);
767                 mini_cleanup (domain);
768                 return 3;
769         }
770
771         if (action == DO_DRAW) {
772                 int part = 0;
773
774                 switch (mono_graph_options) {
775                 case MONO_GRAPH_DTREE:
776                         part = 1;
777                         opt |= MONO_OPT_LOOP;
778                         break;
779                 case MONO_GRAPH_CFG_CODE:
780                         part = 1;
781                         break;
782                 case MONO_GRAPH_CFG_SSA:
783                         part = 2;
784                         break;
785                 case MONO_GRAPH_CFG_OPTCODE:
786                         part = 3;
787                         break;
788                 default:
789                         break;
790                 }
791
792                 cfg = mini_method_compile (method, opt, mono_root_domain, FALSE, part);
793                 if ((mono_graph_options & MONO_GRAPH_CFG_SSA) && !(cfg->comp_done & MONO_COMP_SSA)) {
794                         g_warning ("no SSA info available (use -O=deadce)");
795                         return 1;
796                 }
797                 mono_draw_graph (cfg, mono_graph_options);
798                 mono_destroy_compile (cfg);
799
800         } else if (action == DO_BENCH) {
801                 if (mini_stats_fd) {
802                         const char *n;
803                         double no_opt_time = 0.0;
804                         GTimer *timer = g_timer_new ();
805                         fprintf (mini_stats_fd, "$stattitle = \'Compilations times for %s\';\n", 
806                                  mono_method_full_name (method, TRUE));
807                         fprintf (mini_stats_fd, "@data = (\n");
808                         fprintf (mini_stats_fd, "[");
809                         for (i = 0; i < G_N_ELEMENTS (opt_sets); i++) {
810                                 opt = opt_sets [i];
811                                 n = opt_descr (opt);
812                                 if (!n [0])
813                                         n = "none";
814                                 fprintf (mini_stats_fd, "\"%s\",", n);
815                         }
816                         fprintf (mini_stats_fd, "],\n[");
817
818                         for (i = 0; i < G_N_ELEMENTS (opt_sets); i++) {
819                                 int j;
820                                 double elapsed;
821                                 opt = opt_sets [i];
822                                 g_timer_start (timer);
823                                 for (j = 0; j < count; ++j) {
824                                         cfg = mini_method_compile (method, opt, mono_root_domain, FALSE, 0);
825                                         mono_destroy_compile (cfg);
826                                 }
827                                 g_timer_stop (timer);
828                                 elapsed = g_timer_elapsed (timer, NULL);
829                                 if (!opt)
830                                         no_opt_time = elapsed;
831                                 fprintf (mini_stats_fd, "%f, ", elapsed);
832                         }
833                         fprintf (mini_stats_fd, "]");
834                         if (no_opt_time > 0.0) {
835                                 fprintf (mini_stats_fd, ", \n[");
836                                 for (i = 0; i < G_N_ELEMENTS (opt_sets); i++) 
837                                         fprintf (mini_stats_fd, "%f,", no_opt_time);
838                                 fprintf (mini_stats_fd, "]");
839                         }
840                         fprintf (mini_stats_fd, ");\n");
841                 } else {
842                         for (i = 0; i < count; ++i) {
843                                 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
844                                         (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
845                                         method = mono_marshal_get_native_wrapper (method);
846
847                                 cfg = mini_method_compile (method, opt, mono_root_domain, FALSE, 0);
848                                 mono_destroy_compile (cfg);
849                         }
850                 }
851         } else {
852                 cfg = mini_method_compile (method, opt, mono_root_domain, FALSE, 0);
853                 mono_destroy_compile (cfg);
854         }
855
856         mini_cleanup (domain);
857         return 0;
858 }
859
860 MonoDomain * 
861 mono_jit_init (const char *file)
862 {
863         return mini_init (file);
864 }
865
866 void        
867 mono_jit_cleanup (MonoDomain *domain)
868 {
869         mini_cleanup (domain);
870 }
871
872