5b717fcd5e04dbd5f0ac006d916de79bdb802e9a
[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-2006 Novell, Inc.
10  */
11
12 #include <config.h>
13 #ifdef HAVE_SIGNAL_H
14 #include <signal.h>
15 #endif
16 #if HAVE_SCHED_SETAFFINITY
17 #include <sched.h>
18 #endif
19 #ifdef HAVE_UNISTD_H
20 #include <unistd.h>
21 #endif
22
23 #include <mono/metadata/assembly.h>
24 #include <mono/metadata/loader.h>
25 #include <mono/metadata/tabledefs.h>
26 #include <mono/metadata/class.h>
27 #include <mono/metadata/object.h>
28 #include <mono/metadata/exception.h>
29 #include <mono/metadata/opcodes.h>
30 #include <mono/metadata/mono-endian.h>
31 #include <mono/metadata/tokentype.h>
32 #include <mono/metadata/tabledefs.h>
33 #include <mono/metadata/threads.h>
34 #include <mono/metadata/marshal.h>
35 #include <mono/metadata/socket-io.h>
36 #include <mono/metadata/appdomain.h>
37 #include <mono/metadata/debug-helpers.h>
38 #include <mono/io-layer/io-layer.h>
39 #include "mono/metadata/profiler.h"
40 #include <mono/metadata/profiler-private.h>
41 #include <mono/metadata/mono-config.h>
42 #include <mono/metadata/environment.h>
43 #include <mono/metadata/verify.h>
44 #include <mono/metadata/verify-internals.h>
45 #include <mono/metadata/mono-debug.h>
46 #include <mono/metadata/security-manager.h>
47 #include <mono/metadata/security-core-clr.h>
48 #include <mono/metadata/gc-internals.h>
49 #include <mono/metadata/coree.h>
50 #include <mono/metadata/attach.h>
51 #include "mono/utils/mono-counters.h"
52 #include "mono/utils/mono-hwcap.h"
53 #include "mono/utils/mono-logger-internals.h"
54
55 #include "mini.h"
56 #include "jit.h"
57 #include "aot-compiler.h"
58
59 #include <string.h>
60 #include <ctype.h>
61 #include <locale.h>
62 #include "version.h"
63 #include "debugger-agent.h"
64 #if TARGET_OSX
65 #   include <sys/resource.h>
66 #endif
67
68 static FILE *mini_stats_fd;
69
70 static void mini_usage (void);
71
72 #ifdef HOST_WIN32
73 /* Need this to determine whether to detach console */
74 #include <mono/metadata/cil-coff.h>
75 /* This turns off command line globbing under win32 */
76 int _CRT_glob = 0;
77 #endif
78
79 typedef void (*OptFunc) (const char *p);
80
81 #undef OPTFLAG
82 #ifdef HAVE_ARRAY_ELEM_INIT
83 #define MSGSTRFIELD(line) MSGSTRFIELD1(line)
84 #define MSGSTRFIELD1(line) str##line
85
86 static const struct msgstr_t {
87 #define OPTFLAG(id,shift,name,desc) char MSGSTRFIELD(__LINE__) [sizeof (name) + sizeof (desc)];
88 #include "optflags-def.h"
89 #undef OPTFLAG
90 } opstr = {
91 #define OPTFLAG(id,shift,name,desc) name "\0" desc,
92 #include "optflags-def.h"
93 #undef OPTFLAG
94 };
95 static const gint16 opt_names [] = {
96 #define OPTFLAG(id,shift,name,desc) [(shift)] = offsetof (struct msgstr_t, MSGSTRFIELD(__LINE__)),
97 #include "optflags-def.h"
98 #undef OPTFLAG
99 };
100
101 #define optflag_get_name(id) ((const char*)&opstr + opt_names [(id)])
102 #define optflag_get_desc(id) (optflag_get_name(id) + 1 + strlen (optflag_get_name(id)))
103
104 #else /* !HAVE_ARRAY_ELEM_INIT */
105 typedef struct {
106         const char* name;
107         const char* desc;
108 } OptName;
109
110 #define OPTFLAG(id,shift,name,desc) {name,desc},
111 static const OptName 
112 opt_names [] = {
113 #include "optflags-def.h"
114         {NULL, NULL}
115 };
116 #define optflag_get_name(id) (opt_names [(id)].name)
117 #define optflag_get_desc(id) (opt_names [(id)].desc)
118
119 #endif
120
121 static const OptFunc
122 opt_funcs [sizeof (int) * 8] = {
123         NULL
124 };
125
126 #ifdef __native_client_codegen__
127 extern gint8 nacl_align_byte;
128 #endif
129 #ifdef __native_client__
130 extern char *nacl_mono_path;
131 #endif
132
133 #define DEFAULT_OPTIMIZATIONS ( \
134         MONO_OPT_PEEPHOLE |     \
135         MONO_OPT_CFOLD |        \
136         MONO_OPT_INLINE |       \
137         MONO_OPT_CONSPROP |     \
138         MONO_OPT_COPYPROP |     \
139         MONO_OPT_DEADCE |       \
140         MONO_OPT_BRANCH |       \
141         MONO_OPT_LINEARS |      \
142         MONO_OPT_INTRINS |  \
143         MONO_OPT_LOOP |  \
144         MONO_OPT_EXCEPTION |  \
145     MONO_OPT_CMOV |  \
146         MONO_OPT_GSHARED |      \
147         MONO_OPT_SIMD | \
148         MONO_OPT_ALIAS_ANALYSIS | \
149         MONO_OPT_AOT)
150
151 #define EXCLUDED_FROM_ALL (MONO_OPT_SHARED | MONO_OPT_PRECOMP | MONO_OPT_UNSAFE | MONO_OPT_GSHAREDVT | MONO_OPT_FLOAT32)
152
153 static guint32
154 parse_optimizations (guint32 opt, const char* p, gboolean cpu_opts)
155 {
156         guint32 exclude = 0;
157         const char *n;
158         int i, invert, len;
159
160         /* Initialize the hwcap module if necessary. */
161         mono_hwcap_init ();
162
163         /* call out to cpu detection code here that sets the defaults ... */
164         if (cpu_opts) {
165                 opt |= mono_arch_cpu_optimizations (&exclude);
166                 opt &= ~exclude;
167         }
168         if (!p)
169                 return opt;
170
171         while (*p) {
172                 if (*p == '-') {
173                         p++;
174                         invert = TRUE;
175                 } else {
176                         invert = FALSE;
177                 }
178                 for (i = 0; i < G_N_ELEMENTS (opt_names) && optflag_get_name (i); ++i) {
179                         n = optflag_get_name (i);
180                         len = strlen (n);
181                         if (strncmp (p, n, len) == 0) {
182                                 if (invert)
183                                         opt &= ~ (1 << i);
184                                 else
185                                         opt |= 1 << i;
186                                 p += len;
187                                 if (*p == ',') {
188                                         p++;
189                                         break;
190                                 } else if (*p == '=') {
191                                         p++;
192                                         if (opt_funcs [i])
193                                                 opt_funcs [i] (p);
194                                         while (*p && *p++ != ',');
195                                         break;
196                                 }
197                                 /* error out */
198                                 break;
199                         }
200                 }
201                 if (i == G_N_ELEMENTS (opt_names) || !optflag_get_name (i)) {
202                         if (strncmp (p, "all", 3) == 0) {
203                                 if (invert)
204                                         opt = 0;
205                                 else
206                                         opt = ~(EXCLUDED_FROM_ALL | exclude);
207                                 p += 3;
208                                 if (*p == ',')
209                                         p++;
210                         } else {
211                                 fprintf (stderr, "Invalid optimization name `%s'\n", p);
212                                 exit (1);
213                         }
214                 }
215         }
216         return opt;
217 }
218
219 static gboolean
220 parse_debug_options (const char* p)
221 {
222         MonoDebugOptions *opt = mini_get_debug_options ();
223
224         do {
225                 if (!*p) {
226                         fprintf (stderr, "Syntax error; expected debug option name\n");
227                         return FALSE;
228                 }
229
230                 if (!strncmp (p, "casts", 5)) {
231                         opt->better_cast_details = TRUE;
232                         p += 5;
233                 } else if (!strncmp (p, "mdb-optimizations", 17)) {
234                         opt->mdb_optimizations = TRUE;
235                         p += 17;
236                 } else if (!strncmp (p, "gdb", 3)) {
237                         opt->gdb = TRUE;
238                         p += 3;
239                 } else {
240                         fprintf (stderr, "Invalid debug option `%s', use --help-debug for details\n", p);
241                         return FALSE;
242                 }
243
244                 if (*p == ',') {
245                         p++;
246                         if (!*p) {
247                                 fprintf (stderr, "Syntax error; expected debug option name\n");
248                                 return FALSE;
249                         }
250                 }
251         } while (*p);
252
253         return TRUE;
254 }
255
256 typedef struct {
257         const char name [6];
258         const char desc [18];
259         MonoGraphOptions value;
260 } GraphName;
261
262 static const GraphName 
263 graph_names [] = {
264         {"cfg",      "Control Flow",                            MONO_GRAPH_CFG},
265         {"dtree",    "Dominator Tree",                          MONO_GRAPH_DTREE},
266         {"code",     "CFG showing code",                        MONO_GRAPH_CFG_CODE},
267         {"ssa",      "CFG after SSA",                           MONO_GRAPH_CFG_SSA},
268         {"optc",     "CFG after IR opts",                       MONO_GRAPH_CFG_OPTCODE}
269 };
270
271 static MonoGraphOptions
272 mono_parse_graph_options (const char* p)
273 {
274         const char *n;
275         int i, len;
276
277         for (i = 0; i < G_N_ELEMENTS (graph_names); ++i) {
278                 n = graph_names [i].name;
279                 len = strlen (n);
280                 if (strncmp (p, n, len) == 0)
281                         return graph_names [i].value;
282         }
283
284         fprintf (stderr, "Invalid graph name provided: %s\n", p);
285         exit (1);
286 }
287
288 int
289 mono_parse_default_optimizations (const char* p)
290 {
291         guint32 opt;
292
293         opt = parse_optimizations (DEFAULT_OPTIMIZATIONS, p, TRUE);
294         return opt;
295 }
296
297 char*
298 mono_opt_descr (guint32 flags) {
299         GString *str = g_string_new ("");
300         int i, need_comma;
301
302         need_comma = 0;
303         for (i = 0; i < G_N_ELEMENTS (opt_names); ++i) {
304                 if (flags & (1 << i) && optflag_get_name (i)) {
305                         if (need_comma)
306                                 g_string_append_c (str, ',');
307                         g_string_append (str, optflag_get_name (i));
308                         need_comma = 1;
309                 }
310         }
311         return g_string_free (str, FALSE);
312 }
313
314 static const guint32
315 opt_sets [] = {
316        0,
317        MONO_OPT_PEEPHOLE,
318        MONO_OPT_BRANCH,
319        MONO_OPT_CFOLD,
320        MONO_OPT_FCMOV,
321        MONO_OPT_ALIAS_ANALYSIS,
322 #ifdef MONO_ARCH_SIMD_INTRINSICS
323        MONO_OPT_SIMD,
324        MONO_OPT_SSE2,
325        MONO_OPT_SIMD | MONO_OPT_SSE2,
326 #endif
327        MONO_OPT_BRANCH | MONO_OPT_PEEPHOLE | MONO_OPT_INTRINS,
328        MONO_OPT_BRANCH | MONO_OPT_PEEPHOLE | MONO_OPT_INTRINS | MONO_OPT_ALIAS_ANALYSIS,
329        MONO_OPT_BRANCH | MONO_OPT_PEEPHOLE | MONO_OPT_LINEARS,
330        MONO_OPT_BRANCH | MONO_OPT_PEEPHOLE | MONO_OPT_LINEARS | MONO_OPT_COPYPROP,
331        MONO_OPT_BRANCH | MONO_OPT_PEEPHOLE | MONO_OPT_LINEARS | MONO_OPT_CFOLD,
332        MONO_OPT_BRANCH | MONO_OPT_PEEPHOLE | MONO_OPT_LINEARS | MONO_OPT_COPYPROP | MONO_OPT_CONSPROP | MONO_OPT_DEADCE,
333        MONO_OPT_BRANCH | MONO_OPT_PEEPHOLE | MONO_OPT_LINEARS | MONO_OPT_COPYPROP | MONO_OPT_CONSPROP | MONO_OPT_DEADCE | MONO_OPT_ALIAS_ANALYSIS,
334        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,
335        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_TAILC,
336        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_SSA,
337        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_EXCEPTION,
338        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_EXCEPTION | MONO_OPT_CMOV,
339        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_EXCEPTION | MONO_OPT_ABCREM,
340        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,
341        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,
342        DEFAULT_OPTIMIZATIONS, 
343 };
344
345 typedef int (*TestMethod) (void);
346
347 #if 0
348 static void
349 domain_dump_native_code (MonoDomain *domain) {
350         // need to poke into the domain, move to metadata/domain.c
351         // need to empty jit_info_table and code_mp
352 }
353 #endif
354
355 static void
356 mini_regression_step (MonoImage *image, int verbose, int *total_run, int *total,
357                 guint32 opt_flags,
358                 GTimer *timer, MonoDomain *domain)
359 {
360         int result, expected, failed, cfailed, run, code_size;
361         TestMethod func;
362         double elapsed, comp_time, start_time;
363         char *n;
364         int i;
365
366         mono_set_defaults (verbose, opt_flags);
367         n = mono_opt_descr (opt_flags);
368         g_print ("Test run: image=%s, opts=%s\n", mono_image_get_filename (image), n);
369         g_free (n);
370         cfailed = failed = run = code_size = 0;
371         comp_time = elapsed = 0.0;
372
373         /* fixme: ugly hack - delete all previously compiled methods */
374         if (domain_jit_info (domain)) {
375                 g_hash_table_destroy (domain_jit_info (domain)->jit_trampoline_hash);
376                 domain_jit_info (domain)->jit_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
377                 mono_internal_hash_table_destroy (&(domain->jit_code_hash));
378                 mono_jit_code_hash_init (&(domain->jit_code_hash));
379         }
380
381         g_timer_start (timer);
382         if (mini_stats_fd)
383                 fprintf (mini_stats_fd, "[");
384         for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
385                 MonoError error;
386                 MonoMethod *method = mono_get_method_checked (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL, NULL, &error);
387                 if (!method) {
388                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
389                         continue;
390                 }
391                 if (strncmp (method->name, "test_", 5) == 0) {
392                         MonoCompile *cfg;
393
394                         expected = atoi (method->name + 5);
395                         run++;
396                         start_time = g_timer_elapsed (timer, NULL);
397                         comp_time -= start_time;
398                         cfg = mini_method_compile (method, mono_get_optimizations_for_method (method, opt_flags), mono_get_root_domain (), JIT_FLAG_RUN_CCTORS, 0, -1);
399                         comp_time += g_timer_elapsed (timer, NULL);
400                         if (cfg->exception_type == MONO_EXCEPTION_NONE) {
401                                 if (verbose >= 2)
402                                         g_print ("Running '%s' ...\n", method->name);
403 #ifdef MONO_USE_AOT_COMPILER
404                                 if ((func = (TestMethod)mono_aot_get_method (mono_get_root_domain (), method)))
405                                         ;
406                                 else
407 #endif
408                                         func = (TestMethod)(gpointer)cfg->native_code;
409                                 func = (TestMethod)mono_create_ftnptr (mono_get_root_domain (), func);
410                                 result = func ();
411                                 if (result != expected) {
412                                         failed++;
413                                         g_print ("Test '%s' failed result (got %d, expected %d).\n", method->name, result, expected);
414                                 }
415                                 code_size += cfg->code_len;
416                                 mono_destroy_compile (cfg);
417
418                         } else {
419                                 cfailed++;
420                                 g_print ("Test '%s' failed compilation.\n", method->name);
421                         }
422                         if (mini_stats_fd)
423                                 fprintf (mini_stats_fd, "%f, ",
424                                                 g_timer_elapsed (timer, NULL) - start_time);
425                 }
426         }
427         if (mini_stats_fd)
428                 fprintf (mini_stats_fd, "],\n");
429         g_timer_stop (timer);
430         elapsed = g_timer_elapsed (timer, NULL);
431         if (failed > 0 || cfailed > 0){
432                 g_print ("Results: total tests: %d, failed: %d, cfailed: %d (pass: %.2f%%)\n",
433                                 run, failed, cfailed, 100.0*(run-failed-cfailed)/run);
434         } else {
435                 g_print ("Results: total tests: %d, all pass \n",  run);
436         }
437
438         g_print ("Elapsed time: %f secs (%f, %f), Code size: %d\n\n", elapsed,
439                         elapsed - comp_time, comp_time, code_size);
440         *total += failed + cfailed;
441         *total_run += run;
442 }
443
444 static int
445 mini_regression (MonoImage *image, int verbose, int *total_run)
446 {
447         guint32 i, opt;
448         MonoMethod *method;
449         char *n;
450         GTimer *timer = g_timer_new ();
451         MonoDomain *domain = mono_domain_get ();
452         guint32 exclude = 0;
453         int total;
454
455         /* Note: mono_hwcap_init () called in mono_init () before we get here. */
456         mono_arch_cpu_optimizations (&exclude);
457
458         if (mini_stats_fd) {
459                 fprintf (mini_stats_fd, "$stattitle = \'Mono Benchmark Results (various optimizations)\';\n");
460
461                 fprintf (mini_stats_fd, "$graph->set_legend(qw(");
462                 for (opt = 0; opt < G_N_ELEMENTS (opt_sets); opt++) {
463                         guint32 opt_flags = opt_sets [opt];
464                         n = mono_opt_descr (opt_flags);
465                         if (!n [0])
466                                 n = (char *)"none";
467                         if (opt)
468                                 fprintf (mini_stats_fd, " ");
469                         fprintf (mini_stats_fd, "%s", n);
470                 
471
472                 }
473                 fprintf (mini_stats_fd, "));\n");
474
475                 fprintf (mini_stats_fd, "@data = (\n");
476                 fprintf (mini_stats_fd, "[");
477         }
478
479         /* load the metadata */
480         for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
481                 MonoError error;
482                 method = mono_get_method_checked (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL, NULL, &error);
483                 if (!method) {
484                         mono_error_cleanup (&error);
485                         continue;
486                 }
487                 mono_class_init (method->klass);
488
489                 if (!strncmp (method->name, "test_", 5) && mini_stats_fd) {
490                         fprintf (mini_stats_fd, "\"%s\",", method->name);
491                 }
492         }
493         if (mini_stats_fd)
494                 fprintf (mini_stats_fd, "],\n");
495
496
497         total = 0;
498         *total_run = 0;
499         if (mono_do_single_method_regression) {
500                 GSList *iter;
501
502                 mini_regression_step (image, verbose, total_run, &total,
503                                 0,
504                                 timer, domain);
505                 if (total)
506                         return total;
507                 g_print ("Single method regression: %d methods\n", g_slist_length (mono_single_method_list));
508
509                 for (iter = mono_single_method_list; iter; iter = g_slist_next (iter)) {
510                         char *method_name;
511
512                         mono_current_single_method = (MonoMethod *)iter->data;
513
514                         method_name = mono_method_full_name (mono_current_single_method, TRUE);
515                         g_print ("Current single method: %s\n", method_name);
516                         g_free (method_name);
517
518                         mini_regression_step (image, verbose, total_run, &total,
519                                         0,
520                                         timer, domain);
521                         if (total)
522                                 return total;
523                 }
524         } else {
525                 for (opt = 0; opt < G_N_ELEMENTS (opt_sets); ++opt) {
526                         mini_regression_step (image, verbose, total_run, &total,
527                                         opt_sets [opt] & ~exclude,
528                                         timer, domain);
529                 }
530         }
531
532         if (mini_stats_fd) {
533                 fprintf (mini_stats_fd, ");\n");
534                 fflush (mini_stats_fd);
535         }
536
537         g_timer_destroy (timer);
538         return total;
539 }
540
541 static int
542 mini_regression_list (int verbose, int count, char *images [])
543 {
544         int i, total, total_run, run;
545         MonoAssembly *ass;
546         
547         total_run =  total = 0;
548         for (i = 0; i < count; ++i) {
549                 ass = mono_assembly_open (images [i], NULL);
550                 if (!ass) {
551                         g_warning ("failed to load assembly: %s", images [i]);
552                         continue;
553                 }
554                 total += mini_regression (mono_assembly_get_image (ass), verbose, &run);
555                 total_run += run;
556         }
557         if (total > 0){
558                 g_print ("Overall results: tests: %d, failed: %d, opt combinations: %d (pass: %.2f%%)\n", 
559                          total_run, total, (int)G_N_ELEMENTS (opt_sets), 100.0*(total_run-total)/total_run);
560         } else {
561                 g_print ("Overall results: tests: %d, 100%% pass, opt combinations: %d\n", 
562                          total_run, (int)G_N_ELEMENTS (opt_sets));
563         }
564         
565         return total;
566 }
567
568 #ifdef MONO_JIT_INFO_TABLE_TEST
569 typedef struct _JitInfoData
570 {
571         guint start;
572         guint length;
573         MonoJitInfo *ji;
574         struct _JitInfoData *next;
575 } JitInfoData;
576
577 typedef struct
578 {
579         guint start;
580         guint length;
581         int num_datas;
582         JitInfoData *data;
583 } Region;
584
585 typedef struct
586 {
587         int num_datas;
588         int num_regions;
589         Region *regions;
590         int num_frees;
591         JitInfoData *frees;
592 } ThreadData;
593
594 static int num_threads;
595 static ThreadData *thread_datas;
596 static MonoDomain *test_domain;
597
598 static JitInfoData*
599 alloc_random_data (Region *region)
600 {
601         JitInfoData **data;
602         JitInfoData *prev;
603         guint prev_end;
604         guint next_start;
605         guint max_len;
606         JitInfoData *d;
607         int num_retries = 0;
608         int pos, i;
609
610  restart:
611         prev = NULL;
612         data = &region->data;
613         pos = random () % (region->num_datas + 1);
614         i = 0;
615         while (*data != NULL) {
616                 if (i++ == pos)
617                         break;
618                 prev = *data;
619                 data = &(*data)->next;
620         }
621
622         if (prev == NULL)
623                 g_assert (*data == region->data);
624         else
625                 g_assert (prev->next == *data);
626
627         if (prev == NULL)
628                 prev_end = region->start;
629         else
630                 prev_end = prev->start + prev->length;
631
632         if (*data == NULL)
633                 next_start = region->start + region->length;
634         else
635                 next_start = (*data)->start;
636
637         g_assert (prev_end <= next_start);
638
639         max_len = next_start - prev_end;
640         if (max_len < 128) {
641                 if (++num_retries >= 10)
642                         return NULL;
643                 goto restart;
644         }
645         if (max_len > 1024)
646                 max_len = 1024;
647
648         d = g_new0 (JitInfoData, 1);
649         d->start = prev_end + random () % (max_len / 2);
650         d->length = random () % MIN (max_len, next_start - d->start) + 1;
651
652         g_assert (d->start >= prev_end && d->start + d->length <= next_start);
653
654         d->ji = g_new0 (MonoJitInfo, 1);
655         d->ji->d.method = (MonoMethod*) 0xABadBabe;
656         d->ji->code_start = (gpointer)(gulong) d->start;
657         d->ji->code_size = d->length;
658         d->ji->cas_inited = 1;  /* marks an allocated jit info */
659
660         d->next = *data;
661         *data = d;
662
663         ++region->num_datas;
664
665         return d;
666 }
667
668 static JitInfoData**
669 choose_random_data (Region *region)
670 {
671         int n;
672         int i;
673         JitInfoData **d;
674
675         g_assert (region->num_datas > 0);
676
677         n = random () % region->num_datas;
678
679         for (d = &region->data, i = 0;
680              i < n;
681              d = &(*d)->next, ++i)
682                 ;
683
684         return d;
685 }
686
687 static Region*
688 choose_random_region (ThreadData *td)
689 {
690         return &td->regions [random () % td->num_regions];
691 }
692
693 static ThreadData*
694 choose_random_thread (void)
695 {
696         return &thread_datas [random () % num_threads];
697 }
698
699 static void
700 free_jit_info_data (ThreadData *td, JitInfoData *free)
701 {
702         free->next = td->frees;
703         td->frees = free;
704
705         if (++td->num_frees >= 1000) {
706                 int i;
707
708                 for (i = 0; i < 500; ++i)
709                         free = free->next;
710
711                 while (free->next != NULL) {
712                         JitInfoData *next = free->next->next;
713
714                         //g_free (free->next->ji);
715                         g_free (free->next);
716                         free->next = next;
717
718                         --td->num_frees;
719                 }
720         }
721 }
722
723 #define NUM_THREADS             8
724 #define REGIONS_PER_THREAD      10
725 #define REGION_SIZE             0x10000
726
727 #define MAX_ADDR                (REGION_SIZE * REGIONS_PER_THREAD * NUM_THREADS)
728
729 #define MODE_ALLOC      1
730 #define MODE_FREE       2
731
732 static void
733 test_thread_func (ThreadData *td)
734 {
735         int mode = MODE_ALLOC;
736         int i = 0;
737         gulong lookup_successes = 0, lookup_failures = 0;
738         MonoDomain *domain = test_domain;
739         int thread_num = (int)(td - thread_datas);
740         gboolean modify_thread = thread_num < NUM_THREADS / 2; /* only half of the threads modify the table */
741
742         for (;;) {
743                 int alloc;
744                 int lookup = 1;
745
746                 if (td->num_datas == 0) {
747                         lookup = 0;
748                         alloc = 1;
749                 } else if (modify_thread && random () % 1000 < 5) {
750                         lookup = 0;
751                         if (mode == MODE_ALLOC)
752                                 alloc = (random () % 100) < 70;
753                         else if (mode == MODE_FREE)
754                                 alloc = (random () % 100) < 30;
755                 }
756
757                 if (lookup) {
758                         /* modify threads sometimes look up their own jit infos */
759                         if (modify_thread && random () % 10 < 5) {
760                                 Region *region = choose_random_region (td);
761
762                                 if (region->num_datas > 0) {
763                                         JitInfoData **data = choose_random_data (region);
764                                         guint pos = (*data)->start + random () % (*data)->length;
765                                         MonoJitInfo *ji;
766
767                                         ji = mono_jit_info_table_find (domain, (char*)(gulong) pos);
768
769                                         g_assert (ji->cas_inited);
770                                         g_assert ((*data)->ji == ji);
771                                 }
772                         } else {
773                                 int pos = random () % MAX_ADDR;
774                                 char *addr = (char*)(gulong) pos;
775                                 MonoJitInfo *ji;
776
777                                 ji = mono_jit_info_table_find (domain, addr);
778
779                                 /*
780                                  * FIXME: We are actually not allowed
781                                  * to do this.  By the time we examine
782                                  * the ji another thread might already
783                                  * have removed it.
784                                  */
785                                 if (ji != NULL) {
786                                         g_assert (addr >= (char*)ji->code_start && addr < (char*)ji->code_start + ji->code_size);
787                                         ++lookup_successes;
788                                 } else
789                                         ++lookup_failures;
790                         }
791                 } else if (alloc) {
792                         JitInfoData *data = alloc_random_data (choose_random_region (td));
793
794                         if (data != NULL) {
795                                 mono_jit_info_table_add (domain, data->ji);
796
797                                 ++td->num_datas;
798                         }
799                 } else {
800                         Region *region = choose_random_region (td);
801
802                         if (region->num_datas > 0) {
803                                 JitInfoData **data = choose_random_data (region);
804                                 JitInfoData *free;
805
806                                 mono_jit_info_table_remove (domain, (*data)->ji);
807
808                                 //(*data)->ji->cas_inited = 0; /* marks a free jit info */
809
810                                 free = *data;
811                                 *data = (*data)->next;
812
813                                 free_jit_info_data (td, free);
814
815                                 --region->num_datas;
816                                 --td->num_datas;
817                         }
818                 }
819
820                 if (++i % 100000 == 0) {
821                         int j;
822                         g_print ("num datas %d (%ld - %ld): %d", (int)(td - thread_datas),
823                                  lookup_successes, lookup_failures, td->num_datas);
824                         for (j = 0; j < td->num_regions; ++j)
825                                 g_print ("  %d", td->regions [j].num_datas);
826                         g_print ("\n");
827                 }
828
829                 if (td->num_datas < 100)
830                         mode = MODE_ALLOC;
831                 else if (td->num_datas > 2000)
832                         mode = MODE_FREE;
833         }
834 }
835
836 /*
837 static void
838 small_id_thread_func (gpointer arg)
839 {
840         MonoThread *thread = mono_thread_current ();
841         MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
842
843         g_print ("my small id is %d\n", (int)thread->small_id);
844         mono_hazard_pointer_clear (hp, 1);
845         sleep (3);
846         g_print ("done %d\n", (int)thread->small_id);
847 }
848 */
849
850 static void
851 jit_info_table_test (MonoDomain *domain)
852 {
853         int i;
854
855         g_print ("testing jit_info_table\n");
856
857         num_threads = NUM_THREADS;
858         thread_datas = g_new0 (ThreadData, num_threads);
859
860         for (i = 0; i < num_threads; ++i) {
861                 int j;
862
863                 thread_datas [i].num_regions = REGIONS_PER_THREAD;
864                 thread_datas [i].regions = g_new0 (Region, REGIONS_PER_THREAD);
865
866                 for (j = 0; j < REGIONS_PER_THREAD; ++j) {
867                         thread_datas [i].regions [j].start = (num_threads * j + i) * REGION_SIZE;
868                         thread_datas [i].regions [j].length = REGION_SIZE;
869                 }
870         }
871
872         test_domain = domain;
873
874         /*
875         for (i = 0; i < 72; ++i)
876                 mono_thread_create (domain, small_id_thread_func, NULL);
877
878         sleep (2);
879         */
880
881         for (i = 0; i < num_threads; ++i)
882                 mono_thread_create (domain, test_thread_func, &thread_datas [i]);
883 }
884 #endif
885
886 enum {
887         DO_BENCH,
888         DO_REGRESSION,
889         DO_SINGLE_METHOD_REGRESSION,
890         DO_COMPILE,
891         DO_EXEC,
892         DO_DRAW,
893         DO_DEBUGGER
894 };
895
896 typedef struct CompileAllThreadArgs {
897         MonoAssembly *ass;
898         int verbose;
899         guint32 opts;
900         guint32 recompilation_times;
901 } CompileAllThreadArgs;
902
903 static void
904 compile_all_methods_thread_main_inner (CompileAllThreadArgs *args)
905 {
906         MonoAssembly *ass = args->ass;
907         int verbose = args->verbose;
908         MonoImage *image = mono_assembly_get_image (ass);
909         MonoMethod *method;
910         MonoCompile *cfg;
911         int i, count = 0, fail_count = 0;
912
913         for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
914                 MonoError error;
915                 guint32 token = MONO_TOKEN_METHOD_DEF | (i + 1);
916                 MonoMethodSignature *sig;
917
918                 if (mono_metadata_has_generic_params (image, token))
919                         continue;
920
921                 method = mono_get_method_checked (image, token, NULL, NULL, &error);
922                 if (!method) {
923                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
924                         continue;
925                 }
926                 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
927                     (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
928                     (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
929                     (method->flags & METHOD_ATTRIBUTE_ABSTRACT))
930                         continue;
931
932                 if (method->klass->generic_container)
933                         continue;
934                 sig = mono_method_signature (method);
935                 if (!sig) {
936                         char * desc = mono_method_full_name (method, TRUE);
937                         g_print ("Could not retrieve method signature for %s\n", desc);
938                         g_free (desc);
939                         fail_count ++;
940                         continue;
941                 }
942
943                 if (sig->has_type_parameters)
944                         continue;
945
946                 count++;
947                 if (verbose) {
948                         char * desc = mono_method_full_name (method, TRUE);
949                         g_print ("Compiling %d %s\n", count, desc);
950                         g_free (desc);
951                 }
952                 cfg = mini_method_compile (method, mono_get_optimizations_for_method (method, args->opts), mono_get_root_domain (), (JitFlags)0, 0, -1);
953                 if (cfg->exception_type != MONO_EXCEPTION_NONE) {
954                         printf ("Compilation of %s failed with exception '%s':\n", mono_method_full_name (cfg->method, TRUE), cfg->exception_message);
955                         fail_count ++;
956                 }
957                 mono_destroy_compile (cfg);
958         }
959
960         if (fail_count)
961                 exit (1);
962 }
963
964 static void
965 compile_all_methods_thread_main (CompileAllThreadArgs *args)
966 {
967         guint32 i;
968         for (i = 0; i < args->recompilation_times; ++i)
969                 compile_all_methods_thread_main_inner (args);
970 }
971
972 static void
973 compile_all_methods (MonoAssembly *ass, int verbose, guint32 opts, guint32 recompilation_times)
974 {
975         CompileAllThreadArgs args;
976
977         args.ass = ass;
978         args.verbose = verbose;
979         args.opts = opts;
980         args.recompilation_times = recompilation_times;
981
982         /* 
983          * Need to create a mono thread since compilation might trigger
984          * running of managed code.
985          */
986         mono_thread_create (mono_domain_get (), compile_all_methods_thread_main, &args);
987
988         mono_thread_manage ();
989 }
990
991 /**
992  * mono_jit_exec:
993  * @assembly: reference to an assembly
994  * @argc: argument count
995  * @argv: argument vector
996  *
997  * Start execution of a program.
998  */
999 int 
1000 mono_jit_exec (MonoDomain *domain, MonoAssembly *assembly, int argc, char *argv[])
1001 {
1002         MonoError error;
1003         MonoImage *image = mono_assembly_get_image (assembly);
1004         MonoMethod *method;
1005         guint32 entry = mono_image_get_entry_point (image);
1006
1007         if (!entry) {
1008                 g_print ("Assembly '%s' doesn't have an entry point.\n", mono_image_get_filename (image));
1009                 /* FIXME: remove this silly requirement. */
1010                 mono_environment_exitcode_set (1);
1011                 return 1;
1012         }
1013
1014         method = mono_get_method_checked (image, entry, NULL, NULL, &error);
1015         if (method == NULL){
1016                 g_print ("The entry point method could not be loaded due to %s\n", mono_error_get_message (&error));
1017                 mono_error_cleanup (&error);
1018                 mono_environment_exitcode_set (1);
1019                 return 1;
1020         }
1021         
1022         if (mono_llvm_only) {
1023                 MonoObject *exc;
1024                 int res;
1025
1026                 res = mono_runtime_run_main (method, argc, argv, &exc);
1027                 if (exc) {
1028                         mono_unhandled_exception (exc);
1029                         mono_invoke_unhandled_exception_hook (exc);
1030                         return 1;
1031                 }
1032                 return res;
1033         } else {
1034                 return mono_runtime_run_main (method, argc, argv, NULL);
1035         }
1036 }
1037
1038 typedef struct 
1039 {
1040         MonoDomain *domain;
1041         const char *file;
1042         int argc;
1043         char **argv;
1044         guint32 opts;
1045         char *aot_options;
1046 } MainThreadArgs;
1047
1048 static void main_thread_handler (gpointer user_data)
1049 {
1050         MainThreadArgs *main_args = (MainThreadArgs *)user_data;
1051         MonoAssembly *assembly;
1052
1053         if (mono_compile_aot) {
1054                 int i, res;
1055
1056                 /* Treat the other arguments as assemblies to compile too */
1057                 for (i = 0; i < main_args->argc; ++i) {
1058                         assembly = mono_domain_assembly_open (main_args->domain, main_args->argv [i]);
1059                         if (!assembly) {
1060                                 fprintf (stderr, "Can not open image %s\n", main_args->argv [i]);
1061                                 exit (1);
1062                         }
1063                         /* Check that the assembly loaded matches the filename */
1064                         {
1065                                 MonoImageOpenStatus status;
1066                                 MonoImage *img;
1067
1068                                 img = mono_image_open (main_args->argv [i], &status);
1069                                 if (img && strcmp (img->name, assembly->image->name)) {
1070                                         fprintf (stderr, "Error: Loaded assembly '%s' doesn't match original file name '%s'. Set MONO_PATH to the assembly's location.\n", assembly->image->name, img->name);
1071                                         exit (1);
1072                                 }
1073                         }
1074                         res = mono_compile_assembly (assembly, main_args->opts, main_args->aot_options);
1075                         if (res != 0) {
1076                                 fprintf (stderr, "AOT of image %s failed.\n", main_args->argv [i]);
1077                                 exit (1);
1078                         }
1079                 }
1080         } else {
1081                 assembly = mono_domain_assembly_open (main_args->domain, main_args->file);
1082                 if (!assembly){
1083                         fprintf (stderr, "Can not open image %s\n", main_args->file);
1084                         exit (1);
1085                 }
1086
1087                 /* 
1088                  * This must be done in a thread managed by mono since it can invoke
1089                  * managed code.
1090                  */
1091                 if (main_args->opts & MONO_OPT_PRECOMP)
1092                         mono_precompile_assemblies ();
1093
1094                 mono_jit_exec (main_args->domain, assembly, main_args->argc, main_args->argv);
1095         }
1096 }
1097
1098 static int
1099 load_agent (MonoDomain *domain, char *desc)
1100 {
1101         MonoError error;
1102         char* col = strchr (desc, ':'); 
1103         char *agent, *args;
1104         MonoAssembly *agent_assembly;
1105         MonoImage *image;
1106         MonoMethod *method;
1107         guint32 entry;
1108         MonoArray *main_args;
1109         gpointer pa [1];
1110         MonoImageOpenStatus open_status;
1111
1112         if (col) {
1113                 agent = (char *)g_memdup (desc, col - desc + 1);
1114                 agent [col - desc] = '\0';
1115                 args = col + 1;
1116         } else {
1117                 agent = g_strdup (desc);
1118                 args = NULL;
1119         }
1120
1121         agent_assembly = mono_assembly_open (agent, &open_status);
1122         if (!agent_assembly) {
1123                 fprintf (stderr, "Cannot open agent assembly '%s': %s.\n", agent, mono_image_strerror (open_status));
1124                 g_free (agent);
1125                 return 2;
1126         }
1127
1128         /* 
1129          * Can't use mono_jit_exec (), as it sets things which might confuse the
1130          * real Main method.
1131          */
1132         image = mono_assembly_get_image (agent_assembly);
1133         entry = mono_image_get_entry_point (image);
1134         if (!entry) {
1135                 g_print ("Assembly '%s' doesn't have an entry point.\n", mono_image_get_filename (image));
1136                 g_free (agent);
1137                 return 1;
1138         }
1139
1140         method = mono_get_method_checked (image, entry, NULL, NULL, &error);
1141         if (method == NULL){
1142                 g_print ("The entry point method of assembly '%s' could not be loaded due to %s\n", agent, &error);
1143                 mono_error_cleanup (&error);
1144                 g_free (agent);
1145                 return 1;
1146         }
1147         
1148         mono_thread_set_main (mono_thread_current ());
1149
1150         if (args) {
1151                 main_args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 1);
1152                 mono_array_set (main_args, MonoString*, 0, mono_string_new (domain, args));
1153         } else {
1154                 main_args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
1155         }
1156
1157         g_free (agent);
1158
1159         pa [0] = main_args;
1160         /* Pass NULL as 'exc' so unhandled exceptions abort the runtime */
1161         mono_runtime_invoke_checked (method, NULL, pa, &error);
1162         mono_error_raise_exception (&error); /* FIXME don't raise here */
1163
1164         return 0;
1165 }
1166
1167 static void
1168 mini_usage_jitdeveloper (void)
1169 {
1170         int i;
1171         
1172         fprintf (stdout,
1173                  "Runtime and JIT debugging options:\n"
1174                  "    --breakonex            Inserts a breakpoint on exceptions\n"
1175                  "    --break METHOD         Inserts a breakpoint at METHOD entry\n"
1176                  "    --break-at-bb METHOD N Inserts a breakpoint in METHOD at BB N\n"
1177                  "    --compile METHOD       Just compile METHOD in assembly\n"
1178                  "    --compile-all=N        Compiles all the methods in the assembly multiple times (default: 1)\n"
1179                  "    --ncompile N           Number of times to compile METHOD (default: 1)\n"
1180                  "    --print-vtable         Print the vtable of all used classes\n"
1181                  "    --regression           Runs the regression test contained in the assembly\n"
1182                  "    --single-method=OPTS   Runs regressions with only one method optimized with OPTS at any time\n"
1183                  "    --statfile FILE        Sets the stat file to FILE\n"
1184                  "    --stats                Print statistics about the JIT operations\n"
1185                  "    --wapi=hps|semdel|seminfo IO-layer maintenance\n"
1186                  "    --inject-async-exc METHOD OFFSET Inject an asynchronous exception at METHOD\n"
1187                  "    --verify-all           Run the verifier on all assemblies and methods\n"
1188                  "    --full-aot             Avoid JITting any code\n"
1189                  "    --llvmonly             Use LLVM compiled code only\n"
1190                  "    --agent=ASSEMBLY[:ARG] Loads the specific agent assembly and executes its Main method with the given argument before loading the main assembly.\n"
1191                  "    --no-x86-stack-align   Don't align stack on x86\n"
1192                  "\n"
1193                  "Other options:\n" 
1194                  "    --graph[=TYPE] METHOD  Draws a graph of the specified method:\n");
1195         
1196         for (i = 0; i < G_N_ELEMENTS (graph_names); ++i) {
1197                 fprintf (stdout, "                           %-10s %s\n", graph_names [i].name, graph_names [i].desc);
1198         }
1199 }
1200
1201 static void
1202 mini_usage_list_opt (void)
1203 {
1204         int i;
1205         
1206         for (i = 0; i < G_N_ELEMENTS (opt_names); ++i)
1207                 fprintf (stdout, "                           %-10s %s\n", optflag_get_name (i), optflag_get_desc (i));
1208 }
1209
1210 static void
1211 mini_usage (void)
1212 {
1213         fprintf (stdout,
1214                 "Usage is: mono [options] program [program-options]\n"
1215                 "\n"
1216                 "Development:\n"
1217                 "    --aot[=<options>]      Compiles the assembly to native code\n"
1218                 "    --debug[=<options>]    Enable debugging support, use --help-debug for details\n"
1219                 "    --debugger-agent=options Enable the debugger agent\n"
1220                 "    --profile[=profiler]   Runs in profiling mode with the specified profiler module\n"
1221                 "    --trace[=EXPR]         Enable tracing, use --help-trace for details\n"
1222                 "    --jitmap               Output a jit method map to /tmp/perf-PID.map\n"
1223                 "    --help-devel           Shows more options available to developers\n"
1224 #ifdef __native_client_codegen__
1225                 "    --nacl-align-mask-off  Turn off Native Client 32-byte alignment mask (for debug only)\n"
1226 #endif
1227                 "\n"
1228                 "Runtime:\n"
1229                 "    --config FILE          Loads FILE as the Mono config\n"
1230                 "    --verbose, -v          Increases the verbosity level\n"
1231                 "    --help, -h             Show usage information\n"
1232                 "    --version, -V          Show version information\n"
1233                 "    --runtime=VERSION      Use the VERSION runtime, instead of autodetecting\n"
1234                 "    --optimize=OPT         Turns on or off a specific optimization\n"
1235                 "                           Use --list-opt to get a list of optimizations\n"
1236 #ifndef DISABLE_SECURITY
1237                 "    --security[=mode]      Turns on the unsupported security manager (off by default)\n"
1238                 "                           mode is one of cas, core-clr, verifiable or validil\n"
1239 #endif
1240                 "    --attach=OPTIONS       Pass OPTIONS to the attach agent in the runtime.\n"
1241                 "                           Currently the only supported option is 'disable'.\n"
1242                 "    --llvm, --nollvm       Controls whenever the runtime uses LLVM to compile code.\n"
1243                 "    --gc=[sgen,boehm]      Select SGen or Boehm GC (runs mono or mono-sgen)\n"
1244 #ifdef TARGET_OSX
1245                 "    --arch=[32,64]         Select architecture (runs mono32 or mono64)\n"
1246 #endif
1247 #ifdef HOST_WIN32
1248                 "    --mixed-mode           Enable mixed-mode image support.\n"
1249 #endif
1250           );
1251 }
1252
1253 static void
1254 mini_trace_usage (void)
1255 {
1256         fprintf (stdout,
1257                  "Tracing options:\n"
1258                  "   --trace[=EXPR]        Trace every call, optional EXPR controls the scope\n"
1259                  "\n"
1260                  "EXPR is composed of:\n"
1261                  "    all                  All assemblies\n"
1262                  "    none                 No assemblies\n"
1263                  "    program              Entry point assembly\n"
1264                  "    assembly             Specifies an assembly\n"
1265                  "    wrapper              All wrappers bridging native and managed code\n"
1266                  "    M:Type:Method        Specifies a method\n"
1267                  "    N:Namespace          Specifies a namespace\n"
1268                  "    T:Type               Specifies a type\n"
1269                  "    E:Type               Specifies stack traces for an exception type\n"
1270                  "    EXPR                 Includes expression\n"
1271                  "    -EXPR                Excludes expression\n"
1272                  "    EXPR,EXPR            Multiple expressions\n"
1273                  "    disabled             Don't print any output until toggled via SIGUSR2\n");
1274 }
1275
1276 static void
1277 mini_debug_usage (void)
1278 {
1279         fprintf (stdout,
1280                  "Debugging options:\n"
1281                  "   --debug[=OPTIONS]     Enable debugging support, optional OPTIONS is a comma\n"
1282                  "                         separated list of options\n"
1283                  "\n"
1284                  "OPTIONS is composed of:\n"
1285                  "    casts                Enable more detailed InvalidCastException messages.\n"
1286                  "    mdb-optimizations    Disable some JIT optimizations which are normally\n"
1287                  "                         disabled when running inside the debugger.\n"
1288                  "                         This is useful if you plan to attach to the running\n"
1289                  "                         process with the debugger.\n");
1290 }
1291
1292 #if defined(MONO_ARCH_ARCHITECTURE)
1293 /* Redefine MONO_ARCHITECTURE to include more information */
1294 #undef MONO_ARCHITECTURE
1295 #define MONO_ARCHITECTURE MONO_ARCH_ARCHITECTURE
1296 #endif
1297
1298 static const char info[] =
1299 #ifdef HAVE_KW_THREAD
1300         "\tTLS:           __thread\n"
1301 #else
1302         "\tTLS:           normal\n"
1303 #endif /* HAVE_KW_THREAD */
1304 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
1305     "\tSIGSEGV:       altstack\n"
1306 #else
1307     "\tSIGSEGV:       normal\n"
1308 #endif
1309 #ifdef HAVE_EPOLL
1310     "\tNotifications: epoll\n"
1311 #elif defined(HAVE_KQUEUE)
1312     "\tNotification:  kqueue\n"
1313 #else
1314     "\tNotification:  Thread + polling\n"
1315 #endif
1316         "\tArchitecture:  " MONO_ARCHITECTURE "\n"
1317         "\tDisabled:      " DISABLED_FEATURES "\n"
1318         "\tMisc:          "
1319 #ifdef MONO_SMALL_CONFIG
1320         "smallconfig "
1321 #endif
1322 #ifdef MONO_BIG_ARRAYS
1323         "bigarrays "
1324 #endif
1325 #if defined(MONO_ARCH_SOFT_DEBUG_SUPPORTED) && !defined(DISABLE_SOFT_DEBUG)
1326         "softdebug "
1327 #endif
1328                 "\n"
1329 #ifdef MONO_ARCH_LLVM_SUPPORTED
1330 #ifdef ENABLE_LLVM
1331         "\tLLVM:          yes(" LLVM_VERSION ")\n"
1332 #else
1333         "\tLLVM:          supported, not enabled.\n"
1334 #endif
1335 #endif
1336         "";
1337
1338 #ifndef MONO_ARCH_AOT_SUPPORTED
1339 #define error_if_aot_unsupported() do {fprintf (stderr, "AOT compilation is not supported on this platform.\n"); exit (1);} while (0)
1340 #else
1341 #define error_if_aot_unsupported()
1342 #endif
1343
1344 #ifdef HOST_WIN32
1345 BOOL APIENTRY DllMain (HMODULE module_handle, DWORD reason, LPVOID reserved)
1346 {
1347         if (!mono_gc_dllmain (module_handle, reason, reserved))
1348                 return FALSE;
1349
1350         switch (reason)
1351         {
1352         case DLL_PROCESS_ATTACH:
1353                 mono_install_runtime_load (mini_init);
1354                 break;
1355         case DLL_PROCESS_DETACH:
1356                 if (coree_module_handle)
1357                         FreeLibrary (coree_module_handle);
1358                 break;
1359         case DLL_THREAD_DETACH:
1360                 mono_thread_info_detach ();
1361                 break;
1362         
1363         }
1364         return TRUE;
1365 }
1366 #endif
1367
1368 static gboolean enable_debugging;
1369
1370 /*
1371  * mono_jit_parse_options:
1372  *
1373  *   Process the command line options in ARGV as done by the runtime executable. 
1374  * This should be called before mono_jit_init ().
1375  */
1376 void
1377 mono_jit_parse_options (int argc, char * argv[])
1378 {
1379         int i;
1380         char *trace_options = NULL;
1381         int mini_verbose = 0;
1382         guint32 opt;
1383
1384         /* 
1385          * Some options have no effect here, since they influence the behavior of 
1386          * mono_main ().
1387          */
1388
1389         opt = mono_parse_default_optimizations (NULL);
1390
1391         /* FIXME: Avoid code duplication */
1392         for (i = 0; i < argc; ++i) {
1393                 if (argv [i] [0] != '-')
1394                         break;
1395                 if (strncmp (argv [i], "--debugger-agent=", 17) == 0) {
1396                         MonoDebugOptions *opt = mini_get_debug_options ();
1397
1398                         mono_debugger_agent_parse_options (argv [i] + 17);
1399                         opt->mdb_optimizations = TRUE;
1400                         enable_debugging = TRUE;
1401                 } else if (!strcmp (argv [i], "--soft-breakpoints")) {
1402                         MonoDebugOptions *opt = mini_get_debug_options ();
1403
1404                         opt->soft_breakpoints = TRUE;
1405                         opt->explicit_null_checks = TRUE;
1406                 } else if (strncmp (argv [i], "--optimize=", 11) == 0) {
1407                         opt = parse_optimizations (opt, argv [i] + 11, TRUE);
1408                         mono_set_optimizations (opt);
1409                 } else if (strncmp (argv [i], "-O=", 3) == 0) {
1410                         opt = parse_optimizations (opt, argv [i] + 3, TRUE);
1411                         mono_set_optimizations (opt);
1412                 } else if (strcmp (argv [i], "--trace") == 0) {
1413                         trace_options = (char*)"";
1414                 } else if (strncmp (argv [i], "--trace=", 8) == 0) {
1415                         trace_options = &argv [i][8];
1416                 } else if (strcmp (argv [i], "--verbose") == 0 || strcmp (argv [i], "-v") == 0) {
1417                         mini_verbose++;
1418                 } else if (strcmp (argv [i], "--breakonex") == 0) {
1419                         MonoDebugOptions *opt = mini_get_debug_options ();
1420
1421                         opt->break_on_exc = TRUE;
1422                 } else if (strcmp (argv [i], "--stats") == 0) {
1423                         mono_counters_enable (-1);
1424                         mono_stats.enabled = TRUE;
1425                         mono_jit_stats.enabled = TRUE;
1426                 } else if (strcmp (argv [i], "--break") == 0) {
1427                         if (i+1 >= argc){
1428                                 fprintf (stderr, "Missing method name in --break command line option\n");
1429                                 exit (1);
1430                         }
1431                         
1432                         if (!mono_debugger_insert_breakpoint (argv [++i], FALSE))
1433                                 fprintf (stderr, "Error: invalid method name '%s'\n", argv [i]);
1434                 } else if (strcmp (argv [i], "--llvm") == 0) {
1435 #ifndef MONO_ARCH_LLVM_SUPPORTED
1436                         fprintf (stderr, "Mono Warning: --llvm not supported on this platform.\n");
1437 #elif !defined(ENABLE_LLVM)
1438                         fprintf (stderr, "Mono Warning: --llvm not enabled in this runtime.\n");
1439 #else
1440                         mono_use_llvm = TRUE;
1441 #endif
1442                 } else {
1443                         fprintf (stderr, "Unsupported command line option: '%s'\n", argv [i]);
1444                         exit (1);
1445                 }
1446         }
1447
1448         if (trace_options != NULL) {
1449                 /* 
1450                  * Need to call this before mini_init () so we can trace methods 
1451                  * compiled there too.
1452                  */
1453                 mono_jit_trace_calls = mono_trace_parse_options (trace_options);
1454                 if (mono_jit_trace_calls == NULL)
1455                         exit (1);
1456         }
1457
1458         if (mini_verbose)
1459                 mono_set_verbose_level (mini_verbose);
1460 }
1461
1462 static void
1463 mono_set_use_smp (int use_smp)
1464 {
1465 #if HAVE_SCHED_SETAFFINITY
1466         if (!use_smp) {
1467                 unsigned long proc_mask = 1;
1468 #ifdef GLIBC_BEFORE_2_3_4_SCHED_SETAFFINITY
1469                 sched_setaffinity (getpid(), (gpointer)&proc_mask);
1470 #else
1471                 sched_setaffinity (getpid(), sizeof (unsigned long), (const cpu_set_t *)&proc_mask);
1472 #endif
1473         }
1474 #endif
1475 }
1476
1477 static void
1478 switch_gc (char* argv[], const char* target_gc)
1479 {
1480         GString *path;
1481
1482         if (!strcmp (mono_gc_get_gc_name (), target_gc)) {
1483                 return;
1484         }
1485
1486         path = g_string_new (argv [0]);
1487
1488         /*Running mono without any argument*/
1489         if (strstr (argv [0], "-sgen"))
1490                 g_string_truncate (path, path->len - 5);
1491         else if (strstr (argv [0], "-boehm"))
1492                 g_string_truncate (path, path->len - 6);
1493
1494         g_string_append_c (path, '-');
1495         g_string_append (path, target_gc);
1496
1497 #ifdef HAVE_EXECVP
1498         execvp (path->str, argv);
1499 #else
1500         fprintf (stderr, "Error: --gc=<NAME> option not supported on this platform.\n");
1501 #endif
1502 }
1503
1504 #ifdef TARGET_OSX
1505
1506 /*
1507  * tries to increase the minimum number of files, if the number is below 1024
1508  */
1509 static void
1510 darwin_change_default_file_handles ()
1511 {
1512         struct rlimit limit;
1513         
1514         if (getrlimit (RLIMIT_NOFILE, &limit) == 0){
1515                 if (limit.rlim_cur < 1024){
1516                         limit.rlim_cur = MAX(1024,limit.rlim_cur);
1517                         setrlimit (RLIMIT_NOFILE, &limit);
1518                 }
1519         }
1520 }
1521
1522 static void
1523 switch_arch (char* argv[], const char* target_arch)
1524 {
1525         GString *path;
1526         gsize arch_offset;
1527
1528         if ((strcmp (target_arch, "32") == 0 && strcmp (MONO_ARCHITECTURE, "x86") == 0) ||
1529                 (strcmp (target_arch, "64") == 0 && strcmp (MONO_ARCHITECTURE, "amd64") == 0)) {
1530                 return; /* matching arch loaded */
1531         }
1532
1533         path = g_string_new (argv [0]);
1534         arch_offset = path->len -2; /* last two characters */
1535
1536         /* Remove arch suffix if present */
1537         if (strstr (&path->str[arch_offset], "32") || strstr (&path->str[arch_offset], "64")) {
1538                 g_string_truncate (path, arch_offset);
1539         }
1540
1541         g_string_append (path, target_arch);
1542
1543         if (execvp (path->str, argv) < 0) {
1544                 fprintf (stderr, "Error: --arch=%s Failed to switch to '%s'.\n", target_arch, path->str);
1545                 exit (1);
1546         }
1547 }
1548
1549 #endif
1550 /**
1551  * mono_main:
1552  * @argc: number of arguments in the argv array
1553  * @argv: array of strings containing the startup arguments
1554  *
1555  * Launches the Mono JIT engine and parses all the command line options
1556  * in the same way that the mono command line VM would.
1557  */
1558 int
1559 mono_main (int argc, char* argv[])
1560 {
1561         MainThreadArgs main_args;
1562         MonoAssembly *assembly;
1563         MonoMethodDesc *desc;
1564         MonoMethod *method;
1565         MonoCompile *cfg;
1566         MonoDomain *domain;
1567         MonoImageOpenStatus open_status;
1568         const char* aname, *mname = NULL;
1569         char *config_file = NULL;
1570         int i, count = 1;
1571         guint32 opt, action = DO_EXEC, recompilation_times = 1;
1572         MonoGraphOptions mono_graph_options = (MonoGraphOptions)0;
1573         int mini_verbose = 0;
1574         gboolean enable_profile = FALSE;
1575         char *trace_options = NULL;
1576         char *profile_options = NULL;
1577         char *aot_options = NULL;
1578         char *forced_version = NULL;
1579         GPtrArray *agents = NULL;
1580         char *attach_options = NULL;
1581 #ifdef MONO_JIT_INFO_TABLE_TEST
1582         int test_jit_info_table = FALSE;
1583 #endif
1584 #ifdef HOST_WIN32
1585         int mixed_mode = FALSE;
1586 #endif
1587 #ifdef __native_client__
1588         gboolean nacl_null_checks_off = FALSE;
1589 #endif
1590
1591 #ifdef MOONLIGHT
1592 #ifndef HOST_WIN32
1593         /* stdout defaults to block buffering if it's not writing to a terminal, which
1594          * happens with our test harness: we redirect stdout to capture it. Force line
1595          * buffering in all cases. */
1596         setlinebuf (stdout);
1597 #endif
1598 #endif
1599
1600         setlocale (LC_ALL, "");
1601
1602 #if TARGET_OSX
1603         darwin_change_default_file_handles ();
1604 #endif
1605
1606         if (g_getenv ("MONO_NO_SMP"))
1607                 mono_set_use_smp (FALSE);
1608         
1609         g_log_set_always_fatal (G_LOG_LEVEL_ERROR);
1610         g_log_set_fatal_mask (G_LOG_DOMAIN, G_LOG_LEVEL_ERROR);
1611
1612         opt = mono_parse_default_optimizations (NULL);
1613
1614         for (i = 1; i < argc; ++i) {
1615                 if (argv [i] [0] != '-')
1616                         break;
1617                 if (strcmp (argv [i], "--regression") == 0) {
1618                         action = DO_REGRESSION;
1619                 } else if (strncmp (argv [i], "--single-method=", 16) == 0) {
1620                         char *full_opts = g_strdup_printf ("-all,%s", argv [i] + 16);
1621                         action = DO_SINGLE_METHOD_REGRESSION;
1622                         mono_single_method_regression_opt = parse_optimizations (opt, full_opts, TRUE);
1623                         g_free (full_opts);
1624                 } else if (strcmp (argv [i], "--verbose") == 0 || strcmp (argv [i], "-v") == 0) {
1625                         mini_verbose++;
1626                 } else if (strcmp (argv [i], "--version") == 0 || strcmp (argv [i], "-V") == 0) {
1627                         char *build = mono_get_runtime_build_info ();
1628                         char *gc_descr;
1629
1630                         g_print ("Mono JIT compiler version %s\nCopyright (C) 2002-2014 Novell, Inc, Xamarin Inc and Contributors. www.mono-project.com\n", build);
1631                         g_free (build);
1632                         g_print (info);
1633                         gc_descr = mono_gc_get_description ();
1634                         g_print ("\tGC:            %s\n", gc_descr);
1635                         g_free (gc_descr);
1636                         if (mini_verbose) {
1637                                 const char *cerror;
1638                                 const char *clibpath;
1639                                 mono_init ("mono");
1640                                 cerror = mono_check_corlib_version ();
1641                                 clibpath = mono_defaults.corlib? mono_image_get_filename (mono_defaults.corlib): "unknown";
1642                                 if (cerror) {
1643                                         g_print ("The currently installed mscorlib doesn't match this runtime version.\n");
1644                                         g_print ("The error is: %s\n", cerror);
1645                                         g_print ("mscorlib.dll loaded at: %s\n", clibpath);
1646                                         return 1;
1647                                 }
1648                         }
1649                         return 0;
1650                 } else if (strcmp (argv [i], "--help") == 0 || strcmp (argv [i], "-h") == 0) {
1651                         mini_usage ();
1652                         return 0;
1653                 } else if (strcmp (argv [i], "--help-trace") == 0){
1654                         mini_trace_usage ();
1655                         return 0;
1656                 } else if (strcmp (argv [i], "--help-devel") == 0){
1657                         mini_usage_jitdeveloper ();
1658                         return 0;
1659                 } else if (strcmp (argv [i], "--help-debug") == 0){
1660                         mini_debug_usage ();
1661                         return 0;
1662                 } else if (strcmp (argv [i], "--list-opt") == 0){
1663                         mini_usage_list_opt ();
1664                         return 0;
1665                 } else if (strncmp (argv [i], "--statfile", 10) == 0) {
1666                         if (i + 1 >= argc){
1667                                 fprintf (stderr, "error: --statfile requires a filename argument\n");
1668                                 return 1;
1669                         }
1670                         mini_stats_fd = fopen (argv [++i], "w+");
1671                 } else if (strncmp (argv [i], "--optimize=", 11) == 0) {
1672                         opt = parse_optimizations (opt, argv [i] + 11, TRUE);
1673                 } else if (strncmp (argv [i], "-O=", 3) == 0) {
1674                         opt = parse_optimizations (opt, argv [i] + 3, TRUE);
1675                 } else if (strncmp (argv [i], "--bisect=", 9) == 0) {
1676                         char *param = argv [i] + 9;
1677                         char *sep = strchr (param, ':');
1678                         if (!sep) {
1679                                 fprintf (stderr, "Error: --bisect requires OPT:FILENAME\n");
1680                                 return 1;
1681                         }
1682                         char *opt_string = g_strndup (param, sep - param);
1683                         guint32 opt = parse_optimizations (0, opt_string, FALSE);
1684                         g_free (opt_string);
1685                         mono_set_bisect_methods (opt, sep + 1);
1686                 } else if (strcmp (argv [i], "--gc=sgen") == 0) {
1687                         switch_gc (argv, "sgen");
1688                 } else if (strcmp (argv [i], "--gc=boehm") == 0) {
1689                         switch_gc (argv, "boehm");
1690                 }
1691 #ifdef TARGET_OSX
1692                 else if (strcmp (argv [i], "--arch=32") == 0) {
1693                         switch_arch (argv, "32");
1694                 } else if (strcmp (argv [i], "--arch=64") == 0) {
1695                         switch_arch (argv, "64");
1696                 }
1697 #endif
1698                 else if (strcmp (argv [i], "--config") == 0) {
1699                         if (i +1 >= argc){
1700                                 fprintf (stderr, "error: --config requires a filename argument\n");
1701                                 return 1;
1702                         }
1703                         config_file = argv [++i];
1704 #ifdef HOST_WIN32
1705                 } else if (strcmp (argv [i], "--mixed-mode") == 0) {
1706                         mixed_mode = TRUE;
1707 #endif
1708                 } else if (strcmp (argv [i], "--ncompile") == 0) {
1709                         if (i + 1 >= argc){
1710                                 fprintf (stderr, "error: --ncompile requires an argument\n");
1711                                 return 1;
1712                         }
1713                         count = atoi (argv [++i]);
1714                         action = DO_BENCH;
1715                 } else if (strcmp (argv [i], "--trace") == 0) {
1716                         trace_options = (char*)"";
1717                 } else if (strncmp (argv [i], "--trace=", 8) == 0) {
1718                         trace_options = &argv [i][8];
1719                 } else if (strcmp (argv [i], "--breakonex") == 0) {
1720                         MonoDebugOptions *opt = mini_get_debug_options ();
1721
1722                         opt->break_on_exc = TRUE;
1723                 } else if (strcmp (argv [i], "--break") == 0) {
1724                         if (i+1 >= argc){
1725                                 fprintf (stderr, "Missing method name in --break command line option\n");
1726                                 return 1;
1727                         }
1728                         
1729                         if (!mono_debugger_insert_breakpoint (argv [++i], FALSE))
1730                                 fprintf (stderr, "Error: invalid method name '%s'\n", argv [i]);
1731                 } else if (strcmp (argv [i], "--break-at-bb") == 0) {
1732                         if (i + 2 >= argc) {
1733                                 fprintf (stderr, "Missing method name or bb num in --break-at-bb command line option.");
1734                                 return 1;
1735                         }
1736                         mono_break_at_bb_method = mono_method_desc_new (argv [++i], TRUE);
1737                         if (mono_break_at_bb_method == NULL) {
1738                                 fprintf (stderr, "Method name is in a bad format in --break-at-bb command line option.");
1739                                 return 1;
1740                         }
1741                         mono_break_at_bb_bb_num = atoi (argv [++i]);
1742                 } else if (strcmp (argv [i], "--inject-async-exc") == 0) {
1743                         if (i + 2 >= argc) {
1744                                 fprintf (stderr, "Missing method name or position in --inject-async-exc command line option\n");
1745                                 return 1;
1746                         }
1747                         mono_inject_async_exc_method = mono_method_desc_new (argv [++i], TRUE);
1748                         if (mono_inject_async_exc_method == NULL) {
1749                                 fprintf (stderr, "Method name is in a bad format in --inject-async-exc command line option\n");
1750                                 return 1;
1751                         }
1752                         mono_inject_async_exc_pos = atoi (argv [++i]);
1753                 } else if (strcmp (argv [i], "--verify-all") == 0) {
1754                         mono_verifier_enable_verify_all ();
1755                 } else if (strcmp (argv [i], "--full-aot") == 0) {
1756                         mono_aot_only = TRUE;
1757                 } else if (strcmp (argv [i], "--llvmonly") == 0) {
1758                         mono_aot_only = TRUE;
1759                         mono_llvm_only = TRUE;
1760                 } else if (strcmp (argv [i], "--print-vtable") == 0) {
1761                         mono_print_vtable = TRUE;
1762                 } else if (strcmp (argv [i], "--stats") == 0) {
1763                         mono_counters_enable (-1);
1764                         mono_stats.enabled = TRUE;
1765                         mono_jit_stats.enabled = TRUE;
1766 #ifndef DISABLE_AOT
1767                 } else if (strcmp (argv [i], "--aot") == 0) {
1768                         error_if_aot_unsupported ();
1769                         mono_compile_aot = TRUE;
1770                 } else if (strncmp (argv [i], "--aot=", 6) == 0) {
1771                         error_if_aot_unsupported ();
1772                         mono_compile_aot = TRUE;
1773                         aot_options = &argv [i][6];
1774 #endif
1775                 } else if (strncmp (argv [i], "--compile-all=", 14) == 0) {
1776                         action = DO_COMPILE;
1777                         recompilation_times = atoi (argv [i] + 14);
1778                 } else if (strcmp (argv [i], "--compile-all") == 0) {
1779                         action = DO_COMPILE;
1780                 } else if (strncmp (argv [i], "--runtime=", 10) == 0) {
1781                         forced_version = &argv [i][10];
1782                 } else if (strcmp (argv [i], "--jitmap") == 0) {
1783                         mono_enable_jit_map ();
1784                 } else if (strcmp (argv [i], "--profile") == 0) {
1785                         enable_profile = TRUE;
1786                         profile_options = NULL;
1787                 } else if (strncmp (argv [i], "--profile=", 10) == 0) {
1788                         enable_profile = TRUE;
1789                         profile_options = argv [i] + 10;
1790                 } else if (strncmp (argv [i], "--agent=", 8) == 0) {
1791                         if (agents == NULL)
1792                                 agents = g_ptr_array_new ();
1793                         g_ptr_array_add (agents, argv [i] + 8);
1794                 } else if (strncmp (argv [i], "--attach=", 9) == 0) {
1795                         attach_options = argv [i] + 9;
1796                 } else if (strcmp (argv [i], "--compile") == 0) {
1797                         if (i + 1 >= argc){
1798                                 fprintf (stderr, "error: --compile option requires a method name argument\n");
1799                                 return 1;
1800                         }
1801                         
1802                         mname = argv [++i];
1803                         action = DO_BENCH;
1804                 } else if (strncmp (argv [i], "--graph=", 8) == 0) {
1805                         if (i + 1 >= argc){
1806                                 fprintf (stderr, "error: --graph option requires a method name argument\n");
1807                                 return 1;
1808                         }
1809                         
1810                         mono_graph_options = mono_parse_graph_options (argv [i] + 8);
1811                         mname = argv [++i];
1812                         action = DO_DRAW;
1813                 } else if (strcmp (argv [i], "--graph") == 0) {
1814                         if (i + 1 >= argc){
1815                                 fprintf (stderr, "error: --graph option requires a method name argument\n");
1816                                 return 1;
1817                         }
1818                         
1819                         mname = argv [++i];
1820                         mono_graph_options = MONO_GRAPH_CFG;
1821                         action = DO_DRAW;
1822                 } else if (strcmp (argv [i], "--debug") == 0) {
1823                         enable_debugging = TRUE;
1824                 } else if (strncmp (argv [i], "--debug=", 8) == 0) {
1825                         enable_debugging = TRUE;
1826                         if (!parse_debug_options (argv [i] + 8))
1827                                 return 1;
1828                 } else if (strncmp (argv [i], "--debugger-agent=", 17) == 0) {
1829                         MonoDebugOptions *opt = mini_get_debug_options ();
1830
1831                         mono_debugger_agent_parse_options (argv [i] + 17);
1832                         opt->mdb_optimizations = TRUE;
1833                         enable_debugging = TRUE;
1834                 } else if (strcmp (argv [i], "--security") == 0) {
1835 #ifndef DISABLE_SECURITY
1836                         mono_verifier_set_mode (MONO_VERIFIER_MODE_VERIFIABLE);
1837 #else
1838                         fprintf (stderr, "error: --security: not compiled with security manager support");
1839                         return 1;
1840 #endif
1841                 } else if (strncmp (argv [i], "--security=", 11) == 0) {
1842                         /* Note: validil, and verifiable need to be
1843                            accepted even if DISABLE_SECURITY is defined. */
1844
1845                         if (strcmp (argv [i] + 11, "core-clr") == 0) {
1846 #ifndef DISABLE_SECURITY
1847                                 mono_verifier_set_mode (MONO_VERIFIER_MODE_VERIFIABLE);
1848                                 mono_security_set_mode (MONO_SECURITY_MODE_CORE_CLR);
1849 #else
1850                                 fprintf (stderr, "error: --security: not compiled with CoreCLR support");
1851                                 return 1;
1852 #endif
1853                         } else if (strcmp (argv [i] + 11, "core-clr-test") == 0) {
1854 #ifndef DISABLE_SECURITY
1855                                 /* fixme should we enable verifiable code here?*/
1856                                 mono_security_set_mode (MONO_SECURITY_MODE_CORE_CLR);
1857                                 mono_security_core_clr_test = TRUE;
1858 #else
1859                                 fprintf (stderr, "error: --security: not compiled with CoreCLR support");
1860                                 return 1;
1861 #endif
1862                         } else if (strcmp (argv [i] + 11, "cas") == 0) {
1863 #ifndef DISABLE_SECURITY
1864                                 fprintf (stderr, "warning: --security=cas not supported.");
1865 #else
1866                                 fprintf (stderr, "error: --security: not compiled with CAS support");
1867                                 return 1;
1868 #endif
1869                         } else if (strcmp (argv [i] + 11, "validil") == 0) {
1870                                 mono_verifier_set_mode (MONO_VERIFIER_MODE_VALID);
1871                         } else if (strcmp (argv [i] + 11, "verifiable") == 0) {
1872                                 mono_verifier_set_mode (MONO_VERIFIER_MODE_VERIFIABLE);
1873                         } else {
1874                                 fprintf (stderr, "error: --security= option has invalid argument (cas, core-clr, verifiable or validil)\n");
1875                                 return 1;
1876                         }
1877                 } else if (strcmp (argv [i], "--desktop") == 0) {
1878                         mono_gc_set_desktop_mode ();
1879                         /* Put more desktop-specific optimizations here */
1880                 } else if (strcmp (argv [i], "--server") == 0){
1881                         mono_config_set_server_mode (TRUE);
1882                         /* Put more server-specific optimizations here */
1883                 } else if (strcmp (argv [i], "--inside-mdb") == 0) {
1884                         action = DO_DEBUGGER;
1885                 } else if (strncmp (argv [i], "--wapi=", 7) == 0) {
1886                         fprintf (stderr, "--wapi= option no longer supported\n.");
1887                         return 1;
1888                 } else if (strcmp (argv [i], "--no-x86-stack-align") == 0) {
1889                         mono_do_x86_stack_align = FALSE;
1890 #ifdef MONO_JIT_INFO_TABLE_TEST
1891                 } else if (strcmp (argv [i], "--test-jit-info-table") == 0) {
1892                         test_jit_info_table = TRUE;
1893 #endif
1894                 } else if (strcmp (argv [i], "--llvm") == 0) {
1895 #ifndef MONO_ARCH_LLVM_SUPPORTED
1896                         fprintf (stderr, "Mono Warning: --llvm not supported on this platform.\n");
1897 #elif !defined(ENABLE_LLVM)
1898                         fprintf (stderr, "Mono Warning: --llvm not enabled in this runtime.\n");
1899 #else
1900                         mono_use_llvm = TRUE;
1901 #endif
1902                 } else if (strcmp (argv [i], "--nollvm") == 0){
1903                         mono_use_llvm = FALSE;
1904 #ifdef __native_client_codegen__
1905                 } else if (strcmp (argv [i], "--nacl-align-mask-off") == 0){
1906                         nacl_align_byte = -1; /* 0xff */
1907 #endif
1908 #ifdef __native_client__
1909                 } else if (strcmp (argv [i], "--nacl-mono-path") == 0){
1910                         nacl_mono_path = g_strdup(argv[++i]);
1911                 } else if (strcmp (argv [i], "--nacl-null-checks-off") == 0){
1912                         nacl_null_checks_off = TRUE;
1913 #endif
1914                 } else {
1915                         fprintf (stderr, "Unknown command line option: '%s'\n", argv [i]);
1916                         return 1;
1917                 }
1918         }
1919
1920 #ifdef __native_client_codegen__
1921         if (g_getenv ("MONO_NACL_ALIGN_MASK_OFF"))
1922         {
1923                 nacl_align_byte = -1; /* 0xff */
1924         }
1925         if (!nacl_null_checks_off) {
1926                 MonoDebugOptions *opt = mini_get_debug_options ();
1927                 opt->explicit_null_checks = TRUE;
1928         }
1929 #endif
1930
1931 #ifdef DISABLE_HW_TRAPS
1932         // Signal handlers not available
1933         {
1934                 MonoDebugOptions *opt = mini_get_debug_options ();
1935                 opt->explicit_null_checks = TRUE;
1936         }
1937 #endif
1938
1939         if (!argv [i]) {
1940                 mini_usage ();
1941                 return 1;
1942         }
1943
1944 #if !defined(HOST_WIN32) && defined(HAVE_UNISTD_H)
1945         /*
1946          * If we are not embedded, use the mono runtime executable to run managed exe's.
1947          */
1948         {
1949                 char *runtime_path;
1950
1951                 runtime_path = wapi_process_get_path (getpid ());
1952                 if (runtime_path) {
1953                         wapi_process_set_cli_launcher (runtime_path);
1954                         g_free (runtime_path);
1955                 }
1956         }
1957 #endif
1958
1959         if (g_getenv ("MONO_XDEBUG"))
1960                 enable_debugging = TRUE;
1961
1962 #ifdef MONO_CROSS_COMPILE
1963        if (!mono_compile_aot) {
1964                    fprintf (stderr, "This mono runtime is compiled for cross-compiling. Only the --aot option is supported.\n");
1965                    exit (1);
1966        }
1967 #if SIZEOF_VOID_P == 8 && (defined(TARGET_ARM) || defined(TARGET_X86))
1968        fprintf (stderr, "Can't cross-compile on 64-bit platforms to 32-bit architecture.\n");
1969        exit (1);
1970 #elif SIZEOF_VOID_P == 4 && (defined(TARGET_ARM64) || defined(TARGET_AMD64))
1971        fprintf (stderr, "Can't cross-compile on 32-bit platforms to 64-bit architecture.\n");
1972        exit (1);
1973 #endif
1974 #endif
1975
1976         if (mono_compile_aot || action == DO_EXEC || action == DO_DEBUGGER) {
1977                 g_set_prgname (argv[i]);
1978         }
1979
1980         mono_counters_init ();
1981
1982         /* Set rootdir before loading config */
1983         mono_set_rootdir ();
1984
1985         if (enable_profile)
1986                 mono_profiler_load (profile_options);
1987
1988         mono_attach_parse_options (attach_options);
1989
1990         if (trace_options != NULL){
1991                 /* 
1992                  * Need to call this before mini_init () so we can trace methods 
1993                  * compiled there too.
1994                  */
1995                 mono_jit_trace_calls = mono_trace_parse_options (trace_options);
1996                 if (mono_jit_trace_calls == NULL)
1997                         exit (1);
1998         }
1999
2000 #ifdef DISABLE_JIT
2001         if (!mono_aot_only) {
2002                 fprintf (stderr, "This runtime has been configured with --enable-minimal=jit, so the --full-aot command line option is required.\n");
2003                 exit (1);
2004         }
2005 #endif
2006
2007         if (action == DO_DEBUGGER) {
2008                 enable_debugging = TRUE;
2009                 g_print ("The Mono Debugger is no longer supported.\n");
2010                 return 1;
2011         } else if (enable_debugging)
2012                 mono_debug_init (MONO_DEBUG_FORMAT_MONO);
2013
2014 #ifdef HOST_WIN32
2015         if (mixed_mode)
2016                 mono_load_coree (argv [i]);
2017 #endif
2018
2019         /* Parse gac loading options before loading assemblies. */
2020         if (mono_compile_aot || action == DO_EXEC || action == DO_DEBUGGER) {
2021                 mono_config_parse (config_file);
2022         }
2023
2024         mono_set_defaults (mini_verbose, opt);
2025         domain = mini_init (argv [i], forced_version);
2026
2027         mono_gc_set_stack_end (&domain);
2028
2029         if (agents) {
2030                 int i;
2031
2032                 for (i = 0; i < agents->len; ++i) {
2033                         int res = load_agent (domain, (char*)g_ptr_array_index (agents, i));
2034                         if (res) {
2035                                 g_ptr_array_free (agents, TRUE);
2036                                 mini_cleanup (domain);
2037                                 return 1;
2038                         }
2039                 }
2040
2041                 g_ptr_array_free (agents, TRUE);
2042         }
2043         
2044         switch (action) {
2045         case DO_SINGLE_METHOD_REGRESSION:
2046                 mono_do_single_method_regression = TRUE;
2047         case DO_REGRESSION:
2048                 if (mini_regression_list (mini_verbose, argc -i, argv + i)) {
2049                         g_print ("Regression ERRORS!\n");
2050                         mini_cleanup (domain);
2051                         return 1;
2052                 }
2053                 mini_cleanup (domain);
2054                 return 0;
2055         case DO_BENCH:
2056                 if (argc - i != 1 || mname == NULL) {
2057                         g_print ("Usage: mini --ncompile num --compile method assembly\n");
2058                         mini_cleanup (domain);
2059                         return 1;
2060                 }
2061                 aname = argv [i];
2062                 break;
2063         case DO_COMPILE:
2064                 if (argc - i != 1) {
2065                         mini_usage ();
2066                         mini_cleanup (domain);
2067                         return 1;
2068                 }
2069                 aname = argv [i];
2070                 break;
2071         case DO_DRAW:
2072                 if (argc - i != 1 || mname == NULL) {
2073                         mini_usage ();
2074                         mini_cleanup (domain);
2075                         return 1;
2076                 }
2077                 aname = argv [i];
2078                 break;
2079         default:
2080                 if (argc - i < 1) {
2081                         mini_usage ();
2082                         mini_cleanup (domain);
2083                         return 1;
2084                 }
2085                 aname = argv [i];
2086                 break;
2087         }
2088
2089 #ifdef MONO_JIT_INFO_TABLE_TEST
2090         if (test_jit_info_table)
2091                 jit_info_table_test (domain);
2092 #endif
2093
2094         assembly = mono_assembly_open (aname, &open_status);
2095         if (!assembly) {
2096                 fprintf (stderr, "Cannot open assembly '%s': %s.\n", aname, mono_image_strerror (open_status));
2097                 mini_cleanup (domain);
2098                 return 2;
2099         }
2100
2101         if (trace_options != NULL)
2102                 mono_trace_set_assembly (assembly);
2103
2104         if (mono_compile_aot || action == DO_EXEC) {
2105                 const char *error;
2106
2107                 //mono_set_rootdir ();
2108
2109                 error = mono_check_corlib_version ();
2110                 if (error) {
2111                         fprintf (stderr, "Corlib not in sync with this runtime: %s\n", error);
2112                         fprintf (stderr, "Loaded from: %s\n",
2113                                 mono_defaults.corlib? mono_image_get_filename (mono_defaults.corlib): "unknown");
2114                         fprintf (stderr, "Download a newer corlib or a newer runtime at http://www.mono-project.com/download.\n");
2115                         exit (1);
2116                 }
2117
2118 #ifdef HOST_WIN32
2119                 /* Detach console when executing IMAGE_SUBSYSTEM_WINDOWS_GUI on win32 */
2120                 if (!enable_debugging && !mono_compile_aot && ((MonoCLIImageInfo*)(mono_assembly_get_image (assembly)->image_info))->cli_header.nt.pe_subsys_required == IMAGE_SUBSYSTEM_WINDOWS_GUI)
2121                         FreeConsole ();
2122 #endif
2123
2124                 main_args.domain = domain;
2125                 main_args.file = aname;         
2126                 main_args.argc = argc - i;
2127                 main_args.argv = argv + i;
2128                 main_args.opts = opt;
2129                 main_args.aot_options = aot_options;
2130 #if RUN_IN_SUBTHREAD
2131                 mono_runtime_exec_managed_code (domain, main_thread_handler, &main_args);
2132 #else
2133                 main_thread_handler (&main_args);
2134                 mono_thread_manage ();
2135 #endif
2136
2137                 mini_cleanup (domain);
2138
2139                 /* Look up return value from System.Environment.ExitCode */
2140                 i = mono_environment_exitcode_get ();
2141                 return i;
2142         } else if (action == DO_COMPILE) {
2143                 compile_all_methods (assembly, mini_verbose, opt, recompilation_times);
2144                 mini_cleanup (domain);
2145                 return 0;
2146         } else if (action == DO_DEBUGGER) {
2147                 return 1;
2148         }
2149         desc = mono_method_desc_new (mname, 0);
2150         if (!desc) {
2151                 g_print ("Invalid method name %s\n", mname);
2152                 mini_cleanup (domain);
2153                 return 3;
2154         }
2155         method = mono_method_desc_search_in_image (desc, mono_assembly_get_image (assembly));
2156         if (!method) {
2157                 g_print ("Cannot find method %s\n", mname);
2158                 mini_cleanup (domain);
2159                 return 3;
2160         }
2161
2162 #ifndef DISABLE_JIT
2163         if (action == DO_DRAW) {
2164                 int part = 0;
2165
2166                 switch (mono_graph_options) {
2167                 case MONO_GRAPH_DTREE:
2168                         part = 1;
2169                         opt |= MONO_OPT_LOOP;
2170                         break;
2171                 case MONO_GRAPH_CFG_CODE:
2172                         part = 1;
2173                         break;
2174                 case MONO_GRAPH_CFG_SSA:
2175                         part = 2;
2176                         break;
2177                 case MONO_GRAPH_CFG_OPTCODE:
2178                         part = 3;
2179                         break;
2180                 default:
2181                         break;
2182                 }
2183
2184                 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
2185                         (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
2186                         MonoMethod *nm;
2187                         nm = mono_marshal_get_native_wrapper (method, TRUE, FALSE);
2188                         cfg = mini_method_compile (nm, opt, mono_get_root_domain (), (JitFlags)0, part, -1);
2189                 }
2190                 else
2191                         cfg = mini_method_compile (method, opt, mono_get_root_domain (), (JitFlags)0, part, -1);
2192                 if ((mono_graph_options & MONO_GRAPH_CFG_SSA) && !(cfg->comp_done & MONO_COMP_SSA)) {
2193                         g_warning ("no SSA info available (use -O=deadce)");
2194                         return 1;
2195                 }
2196                 mono_draw_graph (cfg, mono_graph_options);
2197                 mono_destroy_compile (cfg);
2198
2199         } else if (action == DO_BENCH) {
2200                 if (mini_stats_fd) {
2201                         const char *n;
2202                         double no_opt_time = 0.0;
2203                         GTimer *timer = g_timer_new ();
2204                         fprintf (mini_stats_fd, "$stattitle = \'Compilations times for %s\';\n", 
2205                                  mono_method_full_name (method, TRUE));
2206                         fprintf (mini_stats_fd, "@data = (\n");
2207                         fprintf (mini_stats_fd, "[");
2208                         for (i = 0; i < G_N_ELEMENTS (opt_sets); i++) {
2209                                 opt = opt_sets [i];
2210                                 n = mono_opt_descr (opt);
2211                                 if (!n [0])
2212                                         n = "none";
2213                                 fprintf (mini_stats_fd, "\"%s\",", n);
2214                         }
2215                         fprintf (mini_stats_fd, "],\n[");
2216
2217                         for (i = 0; i < G_N_ELEMENTS (opt_sets); i++) {
2218                                 int j;
2219                                 double elapsed;
2220                                 opt = opt_sets [i];
2221                                 g_timer_start (timer);
2222                                 for (j = 0; j < count; ++j) {
2223                                         cfg = mini_method_compile (method, opt, mono_get_root_domain (), (JitFlags)0, 0, -1);
2224                                         mono_destroy_compile (cfg);
2225                                 }
2226                                 g_timer_stop (timer);
2227                                 elapsed = g_timer_elapsed (timer, NULL);
2228                                 if (!opt)
2229                                         no_opt_time = elapsed;
2230                                 fprintf (mini_stats_fd, "%f, ", elapsed);
2231                         }
2232                         fprintf (mini_stats_fd, "]");
2233                         if (no_opt_time > 0.0) {
2234                                 fprintf (mini_stats_fd, ", \n[");
2235                                 for (i = 0; i < G_N_ELEMENTS (opt_sets); i++) 
2236                                         fprintf (mini_stats_fd, "%f,", no_opt_time);
2237                                 fprintf (mini_stats_fd, "]");
2238                         }
2239                         fprintf (mini_stats_fd, ");\n");
2240                 } else {
2241                         for (i = 0; i < count; ++i) {
2242                                 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
2243                                         (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
2244                                         method = mono_marshal_get_native_wrapper (method, TRUE, FALSE);
2245
2246                                 cfg = mini_method_compile (method, opt, mono_get_root_domain (), (JitFlags)0, 0, -1);
2247                                 mono_destroy_compile (cfg);
2248                         }
2249                 }
2250         } else {
2251                 cfg = mini_method_compile (method, opt, mono_get_root_domain (), (JitFlags)0, 0, -1);
2252                 mono_destroy_compile (cfg);
2253         }
2254 #endif
2255
2256         mini_cleanup (domain);
2257         return 0;
2258 }
2259
2260 MonoDomain * 
2261 mono_jit_init (const char *file)
2262 {
2263         return mini_init (file, NULL);
2264 }
2265
2266 /**
2267  * mono_jit_init_version:
2268  * @domain_name: the name of the root domain
2269  * @runtime_version: the version of the runtime to load
2270  *
2271  * Use this version when you want to force a particular runtime
2272  * version to be used.  By default Mono will pick the runtime that is
2273  * referenced by the initial assembly (specified in @file), this
2274  * routine allows programmers to specify the actual runtime to be used
2275  * as the initial runtime is inherited by all future assemblies loaded
2276  * (since Mono does not support having more than one mscorlib runtime
2277  * loaded at once).
2278  *
2279  * The @runtime_version can be one of these strings: "v4.0.30319" for
2280  * desktop, "mobile" for mobile or "moonlight" for Silverlight compat.
2281  * If an unrecognized string is input, the vm will default to desktop.
2282  *
2283  * Returns: the MonoDomain representing the domain where the assembly
2284  * was loaded.
2285  */
2286 MonoDomain * 
2287 mono_jit_init_version (const char *domain_name, const char *runtime_version)
2288 {
2289         return mini_init (domain_name, runtime_version);
2290 }
2291
2292 void        
2293 mono_jit_cleanup (MonoDomain *domain)
2294 {
2295         mono_thread_manage ();
2296
2297         mini_cleanup (domain);
2298 }
2299
2300 void
2301 mono_jit_set_aot_only (gboolean val)
2302 {
2303         mono_aot_only = val;
2304 }
2305
2306 void
2307 mono_jit_set_aot_mode (MonoAotMode mode)
2308 {
2309         mono_aot_mode = mode;
2310         if (mono_aot_mode == MONO_AOT_MODE_LLVMONLY) {
2311                 mono_aot_only = TRUE;
2312                 mono_llvm_only = TRUE;
2313         }
2314 }
2315
2316 /**
2317  * mono_jit_set_trace_options:
2318  * @options: string representing the trace options
2319  *
2320  * Set the options of the tracing engine. This function can be called before initializing
2321  * the mono runtime. See the --trace mono(1) manpage for the options format.
2322  *
2323  * Returns: #TRUE if the options where parsed and set correctly, #FALSE otherwise.
2324  */
2325 gboolean
2326 mono_jit_set_trace_options (const char* options)
2327 {
2328         MonoTraceSpec *trace_opt = mono_trace_parse_options (options);
2329         if (trace_opt == NULL)
2330                 return FALSE;
2331         mono_jit_trace_calls = trace_opt;
2332         return TRUE;
2333 }
2334
2335 /**
2336  * mono_set_signal_chaining:
2337  *
2338  *   Enable/disable signal chaining. This should be called before mono_jit_init ().
2339  * If signal chaining is enabled, the runtime saves the original signal handlers before
2340  * installing its own handlers, and calls the original ones in the following cases:
2341  * - a SIGSEGV/SIGABRT signal received while executing native (i.e. not JITted) code.
2342  * - SIGPROF
2343  * - SIGFPE
2344  * - SIGQUIT
2345  * - SIGUSR2
2346  * Signal chaining only works on POSIX platforms.
2347  */
2348 void
2349 mono_set_signal_chaining (gboolean chain_signals)
2350 {
2351         mono_do_signal_chaining = chain_signals;
2352 }
2353
2354 /**
2355  * mono_set_crash_chaining:
2356  *
2357  * Enable/disable crash chaining due to signals. When a fatal signal is delivered and
2358  * Mono doesn't know how to handle it, it will invoke the crash handler. If chrash chaining
2359  * is enabled, it will first print its crash information and then try to chain with the native handler.
2360  */
2361 void
2362 mono_set_crash_chaining (gboolean chain_crashes)
2363 {
2364         mono_do_crash_chaining = chain_crashes;
2365 }
2366
2367 void
2368 mono_parse_env_options (int *ref_argc, char **ref_argv [])
2369 {
2370         int argc = *ref_argc;
2371         char **argv = *ref_argv;
2372
2373         const char *env_options = g_getenv ("MONO_ENV_OPTIONS");
2374         if (env_options != NULL){
2375                 GPtrArray *array = g_ptr_array_new ();
2376                 GString *buffer = g_string_new ("");
2377                 const char *p;
2378                 unsigned i;
2379                 gboolean in_quotes = FALSE;
2380                 char quote_char = '\0';
2381
2382                 for (p = env_options; *p; p++){
2383                         switch (*p){
2384                         case ' ': case '\t':
2385                                 if (!in_quotes) {
2386                                         if (buffer->len != 0){
2387                                                 g_ptr_array_add (array, g_strdup (buffer->str));
2388                                                 g_string_truncate (buffer, 0);
2389                                         }
2390                                 } else {
2391                                         g_string_append_c (buffer, *p);
2392                                 }
2393                                 break;
2394                         case '\\':
2395                                 if (p [1]){
2396                                         g_string_append_c (buffer, p [1]);
2397                                         p++;
2398                                 }
2399                                 break;
2400                         case '\'':
2401                         case '"':
2402                                 if (in_quotes) {
2403                                         if (quote_char == *p)
2404                                                 in_quotes = FALSE;
2405                                         else
2406                                                 g_string_append_c (buffer, *p);
2407                                 } else {
2408                                         in_quotes = TRUE;
2409                                         quote_char = *p;
2410                                 }
2411                                 break;
2412                         default:
2413                                 g_string_append_c (buffer, *p);
2414                                 break;
2415                         }
2416                 }
2417                 if (in_quotes) {
2418                         fprintf (stderr, "Unmatched quotes in value of MONO_ENV_OPTIONS: [%s]\n", env_options);
2419                         exit (1);
2420                 }
2421                         
2422                 if (buffer->len != 0)
2423                         g_ptr_array_add (array, g_strdup (buffer->str));
2424                 g_string_free (buffer, TRUE);
2425
2426                 if (array->len > 0){
2427                         int new_argc = array->len + argc;
2428                         char **new_argv = g_new (char *, new_argc + 1);
2429                         int j;
2430
2431                         new_argv [0] = argv [0];
2432                         
2433                         /* First the environment variable settings, to allow the command line options to override */
2434                         for (i = 0; i < array->len; i++)
2435                                 new_argv [i+1] = (char *)g_ptr_array_index (array, i);
2436                         i++;
2437                         for (j = 1; j < argc; j++)
2438                                 new_argv [i++] = argv [j];
2439                         new_argv [i] = NULL;
2440
2441                         *ref_argc = new_argc;
2442                         *ref_argv = new_argv;
2443                 }
2444                 g_ptr_array_free (array, TRUE);
2445         }
2446 }