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