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