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