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