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