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