Merge pull request #2520 from kumpera/loader-error-cleanup5
[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         return mono_runtime_run_main (method, argc, argv, NULL);
1023 }
1024
1025 typedef struct 
1026 {
1027         MonoDomain *domain;
1028         const char *file;
1029         int argc;
1030         char **argv;
1031         guint32 opts;
1032         char *aot_options;
1033 } MainThreadArgs;
1034
1035 static void main_thread_handler (gpointer user_data)
1036 {
1037         MainThreadArgs *main_args = (MainThreadArgs *)user_data;
1038         MonoAssembly *assembly;
1039
1040         if (mono_compile_aot) {
1041                 int i, res;
1042
1043                 /* Treat the other arguments as assemblies to compile too */
1044                 for (i = 0; i < main_args->argc; ++i) {
1045                         assembly = mono_domain_assembly_open (main_args->domain, main_args->argv [i]);
1046                         if (!assembly) {
1047                                 fprintf (stderr, "Can not open image %s\n", main_args->argv [i]);
1048                                 exit (1);
1049                         }
1050                         /* Check that the assembly loaded matches the filename */
1051                         {
1052                                 MonoImageOpenStatus status;
1053                                 MonoImage *img;
1054
1055                                 img = mono_image_open (main_args->argv [i], &status);
1056                                 if (img && strcmp (img->name, assembly->image->name)) {
1057                                         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);
1058                                         exit (1);
1059                                 }
1060                         }
1061                         res = mono_compile_assembly (assembly, main_args->opts, main_args->aot_options);
1062                         if (res != 0) {
1063                                 fprintf (stderr, "AOT of image %s failed.\n", main_args->argv [i]);
1064                                 exit (1);
1065                         }
1066                 }
1067         } else {
1068                 assembly = mono_domain_assembly_open (main_args->domain, main_args->file);
1069                 if (!assembly){
1070                         fprintf (stderr, "Can not open image %s\n", main_args->file);
1071                         exit (1);
1072                 }
1073
1074                 /* 
1075                  * This must be done in a thread managed by mono since it can invoke
1076                  * managed code.
1077                  */
1078                 if (main_args->opts & MONO_OPT_PRECOMP)
1079                         mono_precompile_assemblies ();
1080
1081                 mono_jit_exec (main_args->domain, assembly, main_args->argc, main_args->argv);
1082         }
1083 }
1084
1085 static int
1086 load_agent (MonoDomain *domain, char *desc)
1087 {
1088         MonoError error;
1089         char* col = strchr (desc, ':'); 
1090         char *agent, *args;
1091         MonoAssembly *agent_assembly;
1092         MonoImage *image;
1093         MonoMethod *method;
1094         guint32 entry;
1095         MonoArray *main_args;
1096         gpointer pa [1];
1097         MonoImageOpenStatus open_status;
1098
1099         if (col) {
1100                 agent = (char *)g_memdup (desc, col - desc + 1);
1101                 agent [col - desc] = '\0';
1102                 args = col + 1;
1103         } else {
1104                 agent = g_strdup (desc);
1105                 args = NULL;
1106         }
1107
1108         agent_assembly = mono_assembly_open (agent, &open_status);
1109         if (!agent_assembly) {
1110                 fprintf (stderr, "Cannot open agent assembly '%s': %s.\n", agent, mono_image_strerror (open_status));
1111                 g_free (agent);
1112                 return 2;
1113         }
1114
1115         /* 
1116          * Can't use mono_jit_exec (), as it sets things which might confuse the
1117          * real Main method.
1118          */
1119         image = mono_assembly_get_image (agent_assembly);
1120         entry = mono_image_get_entry_point (image);
1121         if (!entry) {
1122                 g_print ("Assembly '%s' doesn't have an entry point.\n", mono_image_get_filename (image));
1123                 g_free (agent);
1124                 return 1;
1125         }
1126
1127         method = mono_get_method_checked (image, entry, NULL, NULL, &error);
1128         if (method == NULL){
1129                 g_print ("The entry point method of assembly '%s' could not be loaded due to %s\n", agent, &error);
1130                 mono_error_cleanup (&error);
1131                 g_free (agent);
1132                 return 1;
1133         }
1134         
1135         mono_thread_set_main (mono_thread_current ());
1136
1137         if (args) {
1138                 main_args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 1);
1139                 mono_array_set (main_args, MonoString*, 0, mono_string_new (domain, args));
1140         } else {
1141                 main_args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
1142         }
1143
1144         g_free (agent);
1145
1146         pa [0] = main_args;
1147         /* Pass NULL as 'exc' so unhandled exceptions abort the runtime */
1148         mono_runtime_invoke (method, NULL, pa, NULL);
1149
1150         return 0;
1151 }
1152
1153 static void
1154 mini_usage_jitdeveloper (void)
1155 {
1156         int i;
1157         
1158         fprintf (stdout,
1159                  "Runtime and JIT debugging options:\n"
1160                  "    --breakonex            Inserts a breakpoint on exceptions\n"
1161                  "    --break METHOD         Inserts a breakpoint at METHOD entry\n"
1162                  "    --break-at-bb METHOD N Inserts a breakpoint in METHOD at BB N\n"
1163                  "    --compile METHOD       Just compile METHOD in assembly\n"
1164                  "    --compile-all=N        Compiles all the methods in the assembly multiple times (default: 1)\n"
1165                  "    --ncompile N           Number of times to compile METHOD (default: 1)\n"
1166                  "    --print-vtable         Print the vtable of all used classes\n"
1167                  "    --regression           Runs the regression test contained in the assembly\n"
1168                  "    --single-method=OPTS   Runs regressions with only one method optimized with OPTS at any time\n"
1169                  "    --statfile FILE        Sets the stat file to FILE\n"
1170                  "    --stats                Print statistics about the JIT operations\n"
1171                  "    --wapi=hps|semdel|seminfo IO-layer maintenance\n"
1172                  "    --inject-async-exc METHOD OFFSET Inject an asynchronous exception at METHOD\n"
1173                  "    --verify-all           Run the verifier on all assemblies and methods\n"
1174                  "    --full-aot             Avoid JITting any code\n"
1175                  "    --llvmonly             Use LLVM compiled code only\n"
1176                  "    --agent=ASSEMBLY[:ARG] Loads the specific agent assembly and executes its Main method with the given argument before loading the main assembly.\n"
1177                  "    --no-x86-stack-align   Don't align stack on x86\n"
1178                  "\n"
1179                  "Other options:\n" 
1180                  "    --graph[=TYPE] METHOD  Draws a graph of the specified method:\n");
1181         
1182         for (i = 0; i < G_N_ELEMENTS (graph_names); ++i) {
1183                 fprintf (stdout, "                           %-10s %s\n", graph_names [i].name, graph_names [i].desc);
1184         }
1185 }
1186
1187 static void
1188 mini_usage_list_opt (void)
1189 {
1190         int i;
1191         
1192         for (i = 0; i < G_N_ELEMENTS (opt_names); ++i)
1193                 fprintf (stdout, "                           %-10s %s\n", optflag_get_name (i), optflag_get_desc (i));
1194 }
1195
1196 static void
1197 mini_usage (void)
1198 {
1199         fprintf (stdout,
1200                 "Usage is: mono [options] program [program-options]\n"
1201                 "\n"
1202                 "Development:\n"
1203                 "    --aot[=<options>]      Compiles the assembly to native code\n"
1204                 "    --debug[=<options>]    Enable debugging support, use --help-debug for details\n"
1205                 "    --debugger-agent=options Enable the debugger agent\n"
1206                 "    --profile[=profiler]   Runs in profiling mode with the specified profiler module\n"
1207                 "    --trace[=EXPR]         Enable tracing, use --help-trace for details\n"
1208                 "    --jitmap               Output a jit method map to /tmp/perf-PID.map\n"
1209                 "    --help-devel           Shows more options available to developers\n"
1210 #ifdef __native_client_codegen__
1211                 "    --nacl-align-mask-off  Turn off Native Client 32-byte alignment mask (for debug only)\n"
1212 #endif
1213                 "\n"
1214                 "Runtime:\n"
1215                 "    --config FILE          Loads FILE as the Mono config\n"
1216                 "    --verbose, -v          Increases the verbosity level\n"
1217                 "    --help, -h             Show usage information\n"
1218                 "    --version, -V          Show version information\n"
1219                 "    --runtime=VERSION      Use the VERSION runtime, instead of autodetecting\n"
1220                 "    --optimize=OPT         Turns on or off a specific optimization\n"
1221                 "                           Use --list-opt to get a list of optimizations\n"
1222 #ifndef DISABLE_SECURITY
1223                 "    --security[=mode]      Turns on the unsupported security manager (off by default)\n"
1224                 "                           mode is one of cas, core-clr, verifiable or validil\n"
1225 #endif
1226                 "    --attach=OPTIONS       Pass OPTIONS to the attach agent in the runtime.\n"
1227                 "                           Currently the only supported option is 'disable'.\n"
1228                 "    --llvm, --nollvm       Controls whenever the runtime uses LLVM to compile code.\n"
1229                 "    --gc=[sgen,boehm]      Select SGen or Boehm GC (runs mono or mono-sgen)\n"
1230 #ifdef TARGET_OSX
1231                 "    --arch=[32,64]         Select architecture (runs mono32 or mono64)\n"
1232 #endif
1233 #ifdef HOST_WIN32
1234                 "    --mixed-mode           Enable mixed-mode image support.\n"
1235 #endif
1236           );
1237 }
1238
1239 static void
1240 mini_trace_usage (void)
1241 {
1242         fprintf (stdout,
1243                  "Tracing options:\n"
1244                  "   --trace[=EXPR]        Trace every call, optional EXPR controls the scope\n"
1245                  "\n"
1246                  "EXPR is composed of:\n"
1247                  "    all                  All assemblies\n"
1248                  "    none                 No assemblies\n"
1249                  "    program              Entry point assembly\n"
1250                  "    assembly             Specifies an assembly\n"
1251                  "    wrapper              All wrappers bridging native and managed code\n"
1252                  "    M:Type:Method        Specifies a method\n"
1253                  "    N:Namespace          Specifies a namespace\n"
1254                  "    T:Type               Specifies a type\n"
1255                  "    E:Type               Specifies stack traces for an exception type\n"
1256                  "    EXPR                 Includes expression\n"
1257                  "    -EXPR                Excludes expression\n"
1258                  "    EXPR,EXPR            Multiple expressions\n"
1259                  "    disabled             Don't print any output until toggled via SIGUSR2\n");
1260 }
1261
1262 static void
1263 mini_debug_usage (void)
1264 {
1265         fprintf (stdout,
1266                  "Debugging options:\n"
1267                  "   --debug[=OPTIONS]     Enable debugging support, optional OPTIONS is a comma\n"
1268                  "                         separated list of options\n"
1269                  "\n"
1270                  "OPTIONS is composed of:\n"
1271                  "    casts                Enable more detailed InvalidCastException messages.\n"
1272                  "    mdb-optimizations    Disable some JIT optimizations which are normally\n"
1273                  "                         disabled when running inside the debugger.\n"
1274                  "                         This is useful if you plan to attach to the running\n"
1275                  "                         process with the debugger.\n");
1276 }
1277
1278 #if defined(MONO_ARCH_ARCHITECTURE)
1279 /* Redefine MONO_ARCHITECTURE to include more information */
1280 #undef MONO_ARCHITECTURE
1281 #define MONO_ARCHITECTURE MONO_ARCH_ARCHITECTURE
1282 #endif
1283
1284 static const char info[] =
1285 #ifdef HAVE_KW_THREAD
1286         "\tTLS:           __thread\n"
1287 #else
1288         "\tTLS:           normal\n"
1289 #endif /* HAVE_KW_THREAD */
1290 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
1291     "\tSIGSEGV:       altstack\n"
1292 #else
1293     "\tSIGSEGV:       normal\n"
1294 #endif
1295 #ifdef HAVE_EPOLL
1296     "\tNotifications: epoll\n"
1297 #elif defined(HAVE_KQUEUE)
1298     "\tNotification:  kqueue\n"
1299 #else
1300     "\tNotification:  Thread + polling\n"
1301 #endif
1302         "\tArchitecture:  " MONO_ARCHITECTURE "\n"
1303         "\tDisabled:      " DISABLED_FEATURES "\n"
1304         "\tMisc:          "
1305 #ifdef MONO_SMALL_CONFIG
1306         "smallconfig "
1307 #endif
1308 #ifdef MONO_BIG_ARRAYS
1309         "bigarrays "
1310 #endif
1311 #if defined(MONO_ARCH_SOFT_DEBUG_SUPPORTED) && !defined(DISABLE_SOFT_DEBUG)
1312         "softdebug "
1313 #endif
1314                 "\n"
1315 #ifdef MONO_ARCH_LLVM_SUPPORTED
1316 #ifdef ENABLE_LLVM
1317         "\tLLVM:          yes(" LLVM_VERSION ")\n"
1318 #else
1319         "\tLLVM:          supported, not enabled.\n"
1320 #endif
1321 #endif
1322         "";
1323
1324 #ifndef MONO_ARCH_AOT_SUPPORTED
1325 #define error_if_aot_unsupported() do {fprintf (stderr, "AOT compilation is not supported on this platform.\n"); exit (1);} while (0)
1326 #else
1327 #define error_if_aot_unsupported()
1328 #endif
1329
1330 #ifdef HOST_WIN32
1331 BOOL APIENTRY DllMain (HMODULE module_handle, DWORD reason, LPVOID reserved)
1332 {
1333         if (!mono_gc_dllmain (module_handle, reason, reserved))
1334                 return FALSE;
1335
1336         switch (reason)
1337         {
1338         case DLL_PROCESS_ATTACH:
1339                 mono_install_runtime_load (mini_init);
1340                 break;
1341         case DLL_PROCESS_DETACH:
1342                 if (coree_module_handle)
1343                         FreeLibrary (coree_module_handle);
1344                 break;
1345         case DLL_THREAD_DETACH:
1346                 mono_thread_info_detach ();
1347                 break;
1348         
1349         }
1350         return TRUE;
1351 }
1352 #endif
1353
1354 static gboolean enable_debugging;
1355
1356 /*
1357  * mono_jit_parse_options:
1358  *
1359  *   Process the command line options in ARGV as done by the runtime executable. 
1360  * This should be called before mono_jit_init ().
1361  */
1362 void
1363 mono_jit_parse_options (int argc, char * argv[])
1364 {
1365         int i;
1366         char *trace_options = NULL;
1367         int mini_verbose = 0;
1368         guint32 opt;
1369
1370         /* 
1371          * Some options have no effect here, since they influence the behavior of 
1372          * mono_main ().
1373          */
1374
1375         opt = mono_parse_default_optimizations (NULL);
1376
1377         /* FIXME: Avoid code duplication */
1378         for (i = 0; i < argc; ++i) {
1379                 if (argv [i] [0] != '-')
1380                         break;
1381                 if (strncmp (argv [i], "--debugger-agent=", 17) == 0) {
1382                         MonoDebugOptions *opt = mini_get_debug_options ();
1383
1384                         mono_debugger_agent_parse_options (argv [i] + 17);
1385                         opt->mdb_optimizations = TRUE;
1386                         enable_debugging = TRUE;
1387                 } else if (!strcmp (argv [i], "--soft-breakpoints")) {
1388                         MonoDebugOptions *opt = mini_get_debug_options ();
1389
1390                         opt->soft_breakpoints = TRUE;
1391                         opt->explicit_null_checks = TRUE;
1392                 } else if (strncmp (argv [i], "--optimize=", 11) == 0) {
1393                         opt = parse_optimizations (opt, argv [i] + 11, TRUE);
1394                         mono_set_optimizations (opt);
1395                 } else if (strncmp (argv [i], "-O=", 3) == 0) {
1396                         opt = parse_optimizations (opt, argv [i] + 3, TRUE);
1397                         mono_set_optimizations (opt);
1398                 } else if (strcmp (argv [i], "--trace") == 0) {
1399                         trace_options = (char*)"";
1400                 } else if (strncmp (argv [i], "--trace=", 8) == 0) {
1401                         trace_options = &argv [i][8];
1402                 } else if (strcmp (argv [i], "--verbose") == 0 || strcmp (argv [i], "-v") == 0) {
1403                         mini_verbose++;
1404                 } else if (strcmp (argv [i], "--breakonex") == 0) {
1405                         MonoDebugOptions *opt = mini_get_debug_options ();
1406
1407                         opt->break_on_exc = TRUE;
1408                 } else if (strcmp (argv [i], "--stats") == 0) {
1409                         mono_counters_enable (-1);
1410                         mono_stats.enabled = TRUE;
1411                         mono_jit_stats.enabled = TRUE;
1412                 } else if (strcmp (argv [i], "--break") == 0) {
1413                         if (i+1 >= argc){
1414                                 fprintf (stderr, "Missing method name in --break command line option\n");
1415                                 exit (1);
1416                         }
1417                         
1418                         if (!mono_debugger_insert_breakpoint (argv [++i], FALSE))
1419                                 fprintf (stderr, "Error: invalid method name '%s'\n", argv [i]);
1420                 } else if (strcmp (argv [i], "--llvm") == 0) {
1421 #ifndef MONO_ARCH_LLVM_SUPPORTED
1422                         fprintf (stderr, "Mono Warning: --llvm not supported on this platform.\n");
1423 #elif !defined(ENABLE_LLVM)
1424                         fprintf (stderr, "Mono Warning: --llvm not enabled in this runtime.\n");
1425 #else
1426                         mono_use_llvm = TRUE;
1427 #endif
1428                 } else {
1429                         fprintf (stderr, "Unsupported command line option: '%s'\n", argv [i]);
1430                         exit (1);
1431                 }
1432         }
1433
1434         if (trace_options != NULL) {
1435                 /* 
1436                  * Need to call this before mini_init () so we can trace methods 
1437                  * compiled there too.
1438                  */
1439                 mono_jit_trace_calls = mono_trace_parse_options (trace_options);
1440                 if (mono_jit_trace_calls == NULL)
1441                         exit (1);
1442         }
1443
1444         if (mini_verbose)
1445                 mono_set_verbose_level (mini_verbose);
1446 }
1447
1448 static void
1449 mono_set_use_smp (int use_smp)
1450 {
1451 #if HAVE_SCHED_SETAFFINITY
1452         if (!use_smp) {
1453                 unsigned long proc_mask = 1;
1454 #ifdef GLIBC_BEFORE_2_3_4_SCHED_SETAFFINITY
1455                 sched_setaffinity (getpid(), (gpointer)&proc_mask);
1456 #else
1457                 sched_setaffinity (getpid(), sizeof (unsigned long), (const cpu_set_t *)&proc_mask);
1458 #endif
1459         }
1460 #endif
1461 }
1462
1463 static void
1464 switch_gc (char* argv[], const char* target_gc)
1465 {
1466         GString *path;
1467
1468         if (!strcmp (mono_gc_get_gc_name (), target_gc)) {
1469                 return;
1470         }
1471
1472         path = g_string_new (argv [0]);
1473
1474         /*Running mono without any argument*/
1475         if (strstr (argv [0], "-sgen"))
1476                 g_string_truncate (path, path->len - 5);
1477         else if (strstr (argv [0], "-boehm"))
1478                 g_string_truncate (path, path->len - 6);
1479
1480         g_string_append_c (path, '-');
1481         g_string_append (path, target_gc);
1482
1483 #ifdef HAVE_EXECVP
1484         execvp (path->str, argv);
1485 #else
1486         fprintf (stderr, "Error: --gc=<NAME> option not supported on this platform.\n");
1487 #endif
1488 }
1489
1490 #ifdef TARGET_OSX
1491
1492 /*
1493  * tries to increase the minimum number of files, if the number is below 1024
1494  */
1495 static void
1496 darwin_change_default_file_handles ()
1497 {
1498         struct rlimit limit;
1499         
1500         if (getrlimit (RLIMIT_NOFILE, &limit) == 0){
1501                 if (limit.rlim_cur < 1024){
1502                         limit.rlim_cur = MAX(1024,limit.rlim_cur);
1503                         setrlimit (RLIMIT_NOFILE, &limit);
1504                 }
1505         }
1506 }
1507
1508 static void
1509 switch_arch (char* argv[], const char* target_arch)
1510 {
1511         GString *path;
1512         gsize arch_offset;
1513
1514         if ((strcmp (target_arch, "32") == 0 && strcmp (MONO_ARCHITECTURE, "x86") == 0) ||
1515                 (strcmp (target_arch, "64") == 0 && strcmp (MONO_ARCHITECTURE, "amd64") == 0)) {
1516                 return; /* matching arch loaded */
1517         }
1518
1519         path = g_string_new (argv [0]);
1520         arch_offset = path->len -2; /* last two characters */
1521
1522         /* Remove arch suffix if present */
1523         if (strstr (&path->str[arch_offset], "32") || strstr (&path->str[arch_offset], "64")) {
1524                 g_string_truncate (path, arch_offset);
1525         }
1526
1527         g_string_append (path, target_arch);
1528
1529         if (execvp (path->str, argv) < 0) {
1530                 fprintf (stderr, "Error: --arch=%s Failed to switch to '%s'.\n", target_arch, path->str);
1531                 exit (1);
1532         }
1533 }
1534
1535 #endif
1536 /**
1537  * mono_main:
1538  * @argc: number of arguments in the argv array
1539  * @argv: array of strings containing the startup arguments
1540  *
1541  * Launches the Mono JIT engine and parses all the command line options
1542  * in the same way that the mono command line VM would.
1543  */
1544 int
1545 mono_main (int argc, char* argv[])
1546 {
1547         MainThreadArgs main_args;
1548         MonoAssembly *assembly;
1549         MonoMethodDesc *desc;
1550         MonoMethod *method;
1551         MonoCompile *cfg;
1552         MonoDomain *domain;
1553         MonoImageOpenStatus open_status;
1554         const char* aname, *mname = NULL;
1555         char *config_file = NULL;
1556         int i, count = 1;
1557         guint32 opt, action = DO_EXEC, recompilation_times = 1;
1558         MonoGraphOptions mono_graph_options = (MonoGraphOptions)0;
1559         int mini_verbose = 0;
1560         gboolean enable_profile = FALSE;
1561         char *trace_options = NULL;
1562         char *profile_options = NULL;
1563         char *aot_options = NULL;
1564         char *forced_version = NULL;
1565         GPtrArray *agents = NULL;
1566         char *attach_options = NULL;
1567 #ifdef MONO_JIT_INFO_TABLE_TEST
1568         int test_jit_info_table = FALSE;
1569 #endif
1570 #ifdef HOST_WIN32
1571         int mixed_mode = FALSE;
1572 #endif
1573 #ifdef __native_client__
1574         gboolean nacl_null_checks_off = FALSE;
1575 #endif
1576
1577 #ifdef MOONLIGHT
1578 #ifndef HOST_WIN32
1579         /* stdout defaults to block buffering if it's not writing to a terminal, which
1580          * happens with our test harness: we redirect stdout to capture it. Force line
1581          * buffering in all cases. */
1582         setlinebuf (stdout);
1583 #endif
1584 #endif
1585
1586         setlocale (LC_ALL, "");
1587
1588 #if TARGET_OSX
1589         darwin_change_default_file_handles ();
1590 #endif
1591
1592         if (g_getenv ("MONO_NO_SMP"))
1593                 mono_set_use_smp (FALSE);
1594         
1595         g_log_set_always_fatal (G_LOG_LEVEL_ERROR);
1596         g_log_set_fatal_mask (G_LOG_DOMAIN, G_LOG_LEVEL_ERROR);
1597
1598         opt = mono_parse_default_optimizations (NULL);
1599
1600         for (i = 1; i < argc; ++i) {
1601                 if (argv [i] [0] != '-')
1602                         break;
1603                 if (strcmp (argv [i], "--regression") == 0) {
1604                         action = DO_REGRESSION;
1605                 } else if (strncmp (argv [i], "--single-method=", 16) == 0) {
1606                         char *full_opts = g_strdup_printf ("-all,%s", argv [i] + 16);
1607                         action = DO_SINGLE_METHOD_REGRESSION;
1608                         mono_single_method_regression_opt = parse_optimizations (opt, full_opts, TRUE);
1609                         g_free (full_opts);
1610                 } else if (strcmp (argv [i], "--verbose") == 0 || strcmp (argv [i], "-v") == 0) {
1611                         mini_verbose++;
1612                 } else if (strcmp (argv [i], "--version") == 0 || strcmp (argv [i], "-V") == 0) {
1613                         char *build = mono_get_runtime_build_info ();
1614                         char *gc_descr;
1615
1616                         g_print ("Mono JIT compiler version %s\nCopyright (C) 2002-2014 Novell, Inc, Xamarin Inc and Contributors. www.mono-project.com\n", build);
1617                         g_free (build);
1618                         g_print (info);
1619                         gc_descr = mono_gc_get_description ();
1620                         g_print ("\tGC:            %s\n", gc_descr);
1621                         g_free (gc_descr);
1622                         if (mini_verbose) {
1623                                 const char *cerror;
1624                                 const char *clibpath;
1625                                 mono_init ("mono");
1626                                 cerror = mono_check_corlib_version ();
1627                                 clibpath = mono_defaults.corlib? mono_image_get_filename (mono_defaults.corlib): "unknown";
1628                                 if (cerror) {
1629                                         g_print ("The currently installed mscorlib doesn't match this runtime version.\n");
1630                                         g_print ("The error is: %s\n", cerror);
1631                                         g_print ("mscorlib.dll loaded at: %s\n", clibpath);
1632                                         return 1;
1633                                 }
1634                         }
1635                         return 0;
1636                 } else if (strcmp (argv [i], "--help") == 0 || strcmp (argv [i], "-h") == 0) {
1637                         mini_usage ();
1638                         return 0;
1639                 } else if (strcmp (argv [i], "--help-trace") == 0){
1640                         mini_trace_usage ();
1641                         return 0;
1642                 } else if (strcmp (argv [i], "--help-devel") == 0){
1643                         mini_usage_jitdeveloper ();
1644                         return 0;
1645                 } else if (strcmp (argv [i], "--help-debug") == 0){
1646                         mini_debug_usage ();
1647                         return 0;
1648                 } else if (strcmp (argv [i], "--list-opt") == 0){
1649                         mini_usage_list_opt ();
1650                         return 0;
1651                 } else if (strncmp (argv [i], "--statfile", 10) == 0) {
1652                         if (i + 1 >= argc){
1653                                 fprintf (stderr, "error: --statfile requires a filename argument\n");
1654                                 return 1;
1655                         }
1656                         mini_stats_fd = fopen (argv [++i], "w+");
1657                 } else if (strncmp (argv [i], "--optimize=", 11) == 0) {
1658                         opt = parse_optimizations (opt, argv [i] + 11, TRUE);
1659                 } else if (strncmp (argv [i], "-O=", 3) == 0) {
1660                         opt = parse_optimizations (opt, argv [i] + 3, TRUE);
1661                 } else if (strncmp (argv [i], "--bisect=", 9) == 0) {
1662                         char *param = argv [i] + 9;
1663                         char *sep = strchr (param, ':');
1664                         if (!sep) {
1665                                 fprintf (stderr, "Error: --bisect requires OPT:FILENAME\n");
1666                                 return 1;
1667                         }
1668                         char *opt_string = g_strndup (param, sep - param);
1669                         guint32 opt = parse_optimizations (0, opt_string, FALSE);
1670                         g_free (opt_string);
1671                         mono_set_bisect_methods (opt, sep + 1);
1672                 } else if (strcmp (argv [i], "--gc=sgen") == 0) {
1673                         switch_gc (argv, "sgen");
1674                 } else if (strcmp (argv [i], "--gc=boehm") == 0) {
1675                         switch_gc (argv, "boehm");
1676                 }
1677 #ifdef TARGET_OSX
1678                 else if (strcmp (argv [i], "--arch=32") == 0) {
1679                         switch_arch (argv, "32");
1680                 } else if (strcmp (argv [i], "--arch=64") == 0) {
1681                         switch_arch (argv, "64");
1682                 }
1683 #endif
1684                 else if (strcmp (argv [i], "--config") == 0) {
1685                         if (i +1 >= argc){
1686                                 fprintf (stderr, "error: --config requires a filename argument\n");
1687                                 return 1;
1688                         }
1689                         config_file = argv [++i];
1690 #ifdef HOST_WIN32
1691                 } else if (strcmp (argv [i], "--mixed-mode") == 0) {
1692                         mixed_mode = TRUE;
1693 #endif
1694                 } else if (strcmp (argv [i], "--ncompile") == 0) {
1695                         if (i + 1 >= argc){
1696                                 fprintf (stderr, "error: --ncompile requires an argument\n");
1697                                 return 1;
1698                         }
1699                         count = atoi (argv [++i]);
1700                         action = DO_BENCH;
1701                 } else if (strcmp (argv [i], "--trace") == 0) {
1702                         trace_options = (char*)"";
1703                 } else if (strncmp (argv [i], "--trace=", 8) == 0) {
1704                         trace_options = &argv [i][8];
1705                 } else if (strcmp (argv [i], "--breakonex") == 0) {
1706                         MonoDebugOptions *opt = mini_get_debug_options ();
1707
1708                         opt->break_on_exc = TRUE;
1709                 } else if (strcmp (argv [i], "--break") == 0) {
1710                         if (i+1 >= argc){
1711                                 fprintf (stderr, "Missing method name in --break command line option\n");
1712                                 return 1;
1713                         }
1714                         
1715                         if (!mono_debugger_insert_breakpoint (argv [++i], FALSE))
1716                                 fprintf (stderr, "Error: invalid method name '%s'\n", argv [i]);
1717                 } else if (strcmp (argv [i], "--break-at-bb") == 0) {
1718                         if (i + 2 >= argc) {
1719                                 fprintf (stderr, "Missing method name or bb num in --break-at-bb command line option.");
1720                                 return 1;
1721                         }
1722                         mono_break_at_bb_method = mono_method_desc_new (argv [++i], TRUE);
1723                         if (mono_break_at_bb_method == NULL) {
1724                                 fprintf (stderr, "Method name is in a bad format in --break-at-bb command line option.");
1725                                 return 1;
1726                         }
1727                         mono_break_at_bb_bb_num = atoi (argv [++i]);
1728                 } else if (strcmp (argv [i], "--inject-async-exc") == 0) {
1729                         if (i + 2 >= argc) {
1730                                 fprintf (stderr, "Missing method name or position in --inject-async-exc command line option\n");
1731                                 return 1;
1732                         }
1733                         mono_inject_async_exc_method = mono_method_desc_new (argv [++i], TRUE);
1734                         if (mono_inject_async_exc_method == NULL) {
1735                                 fprintf (stderr, "Method name is in a bad format in --inject-async-exc command line option\n");
1736                                 return 1;
1737                         }
1738                         mono_inject_async_exc_pos = atoi (argv [++i]);
1739                 } else if (strcmp (argv [i], "--verify-all") == 0) {
1740                         mono_verifier_enable_verify_all ();
1741                 } else if (strcmp (argv [i], "--full-aot") == 0) {
1742                         mono_aot_only = TRUE;
1743                 } else if (strcmp (argv [i], "--llvmonly") == 0) {
1744                         mono_aot_only = TRUE;
1745                         mono_llvm_only = TRUE;
1746                 } else if (strcmp (argv [i], "--print-vtable") == 0) {
1747                         mono_print_vtable = TRUE;
1748                 } else if (strcmp (argv [i], "--stats") == 0) {
1749                         mono_counters_enable (-1);
1750                         mono_stats.enabled = TRUE;
1751                         mono_jit_stats.enabled = TRUE;
1752 #ifndef DISABLE_AOT
1753                 } else if (strcmp (argv [i], "--aot") == 0) {
1754                         error_if_aot_unsupported ();
1755                         mono_compile_aot = TRUE;
1756                 } else if (strncmp (argv [i], "--aot=", 6) == 0) {
1757                         error_if_aot_unsupported ();
1758                         mono_compile_aot = TRUE;
1759                         aot_options = &argv [i][6];
1760 #endif
1761                 } else if (strncmp (argv [i], "--compile-all=", 14) == 0) {
1762                         action = DO_COMPILE;
1763                         recompilation_times = atoi (argv [i] + 14);
1764                 } else if (strcmp (argv [i], "--compile-all") == 0) {
1765                         action = DO_COMPILE;
1766                 } else if (strncmp (argv [i], "--runtime=", 10) == 0) {
1767                         forced_version = &argv [i][10];
1768                 } else if (strcmp (argv [i], "--jitmap") == 0) {
1769                         mono_enable_jit_map ();
1770                 } else if (strcmp (argv [i], "--profile") == 0) {
1771                         enable_profile = TRUE;
1772                         profile_options = NULL;
1773                 } else if (strncmp (argv [i], "--profile=", 10) == 0) {
1774                         enable_profile = TRUE;
1775                         profile_options = argv [i] + 10;
1776                 } else if (strncmp (argv [i], "--agent=", 8) == 0) {
1777                         if (agents == NULL)
1778                                 agents = g_ptr_array_new ();
1779                         g_ptr_array_add (agents, argv [i] + 8);
1780                 } else if (strncmp (argv [i], "--attach=", 9) == 0) {
1781                         attach_options = argv [i] + 9;
1782                 } else if (strcmp (argv [i], "--compile") == 0) {
1783                         if (i + 1 >= argc){
1784                                 fprintf (stderr, "error: --compile option requires a method name argument\n");
1785                                 return 1;
1786                         }
1787                         
1788                         mname = argv [++i];
1789                         action = DO_BENCH;
1790                 } else if (strncmp (argv [i], "--graph=", 8) == 0) {
1791                         if (i + 1 >= argc){
1792                                 fprintf (stderr, "error: --graph option requires a method name argument\n");
1793                                 return 1;
1794                         }
1795                         
1796                         mono_graph_options = mono_parse_graph_options (argv [i] + 8);
1797                         mname = argv [++i];
1798                         action = DO_DRAW;
1799                 } else if (strcmp (argv [i], "--graph") == 0) {
1800                         if (i + 1 >= argc){
1801                                 fprintf (stderr, "error: --graph option requires a method name argument\n");
1802                                 return 1;
1803                         }
1804                         
1805                         mname = argv [++i];
1806                         mono_graph_options = MONO_GRAPH_CFG;
1807                         action = DO_DRAW;
1808                 } else if (strcmp (argv [i], "--debug") == 0) {
1809                         enable_debugging = TRUE;
1810                 } else if (strncmp (argv [i], "--debug=", 8) == 0) {
1811                         enable_debugging = TRUE;
1812                         if (!parse_debug_options (argv [i] + 8))
1813                                 return 1;
1814                 } else if (strncmp (argv [i], "--debugger-agent=", 17) == 0) {
1815                         MonoDebugOptions *opt = mini_get_debug_options ();
1816
1817                         mono_debugger_agent_parse_options (argv [i] + 17);
1818                         opt->mdb_optimizations = TRUE;
1819                         enable_debugging = TRUE;
1820                 } else if (strcmp (argv [i], "--security") == 0) {
1821 #ifndef DISABLE_SECURITY
1822                         mono_verifier_set_mode (MONO_VERIFIER_MODE_VERIFIABLE);
1823 #else
1824                         fprintf (stderr, "error: --security: not compiled with security manager support");
1825                         return 1;
1826 #endif
1827                 } else if (strncmp (argv [i], "--security=", 11) == 0) {
1828                         /* Note: validil, and verifiable need to be
1829                            accepted even if DISABLE_SECURITY is defined. */
1830
1831                         if (strcmp (argv [i] + 11, "core-clr") == 0) {
1832 #ifndef DISABLE_SECURITY
1833                                 mono_verifier_set_mode (MONO_VERIFIER_MODE_VERIFIABLE);
1834                                 mono_security_set_mode (MONO_SECURITY_MODE_CORE_CLR);
1835 #else
1836                                 fprintf (stderr, "error: --security: not compiled with CoreCLR support");
1837                                 return 1;
1838 #endif
1839                         } else if (strcmp (argv [i] + 11, "core-clr-test") == 0) {
1840 #ifndef DISABLE_SECURITY
1841                                 /* fixme should we enable verifiable code here?*/
1842                                 mono_security_set_mode (MONO_SECURITY_MODE_CORE_CLR);
1843                                 mono_security_core_clr_test = TRUE;
1844 #else
1845                                 fprintf (stderr, "error: --security: not compiled with CoreCLR support");
1846                                 return 1;
1847 #endif
1848                         } else if (strcmp (argv [i] + 11, "cas") == 0) {
1849 #ifndef DISABLE_SECURITY
1850                                 fprintf (stderr, "warning: --security=cas not supported.");
1851 #else
1852                                 fprintf (stderr, "error: --security: not compiled with CAS support");
1853                                 return 1;
1854 #endif
1855                         } else if (strcmp (argv [i] + 11, "validil") == 0) {
1856                                 mono_verifier_set_mode (MONO_VERIFIER_MODE_VALID);
1857                         } else if (strcmp (argv [i] + 11, "verifiable") == 0) {
1858                                 mono_verifier_set_mode (MONO_VERIFIER_MODE_VERIFIABLE);
1859                         } else {
1860                                 fprintf (stderr, "error: --security= option has invalid argument (cas, core-clr, verifiable or validil)\n");
1861                                 return 1;
1862                         }
1863                 } else if (strcmp (argv [i], "--desktop") == 0) {
1864                         mono_gc_set_desktop_mode ();
1865                         /* Put more desktop-specific optimizations here */
1866                 } else if (strcmp (argv [i], "--server") == 0){
1867                         mono_config_set_server_mode (TRUE);
1868                         /* Put more server-specific optimizations here */
1869                 } else if (strcmp (argv [i], "--inside-mdb") == 0) {
1870                         action = DO_DEBUGGER;
1871                 } else if (strncmp (argv [i], "--wapi=", 7) == 0) {
1872                         fprintf (stderr, "--wapi= option no longer supported\n.");
1873                         return 1;
1874                 } else if (strcmp (argv [i], "--no-x86-stack-align") == 0) {
1875                         mono_do_x86_stack_align = FALSE;
1876 #ifdef MONO_JIT_INFO_TABLE_TEST
1877                 } else if (strcmp (argv [i], "--test-jit-info-table") == 0) {
1878                         test_jit_info_table = TRUE;
1879 #endif
1880                 } else if (strcmp (argv [i], "--llvm") == 0) {
1881 #ifndef MONO_ARCH_LLVM_SUPPORTED
1882                         fprintf (stderr, "Mono Warning: --llvm not supported on this platform.\n");
1883 #elif !defined(ENABLE_LLVM)
1884                         fprintf (stderr, "Mono Warning: --llvm not enabled in this runtime.\n");
1885 #else
1886                         mono_use_llvm = TRUE;
1887 #endif
1888                 } else if (strcmp (argv [i], "--nollvm") == 0){
1889                         mono_use_llvm = FALSE;
1890 #ifdef __native_client_codegen__
1891                 } else if (strcmp (argv [i], "--nacl-align-mask-off") == 0){
1892                         nacl_align_byte = -1; /* 0xff */
1893 #endif
1894 #ifdef __native_client__
1895                 } else if (strcmp (argv [i], "--nacl-mono-path") == 0){
1896                         nacl_mono_path = g_strdup(argv[++i]);
1897                 } else if (strcmp (argv [i], "--nacl-null-checks-off") == 0){
1898                         nacl_null_checks_off = TRUE;
1899 #endif
1900                 } else {
1901                         fprintf (stderr, "Unknown command line option: '%s'\n", argv [i]);
1902                         return 1;
1903                 }
1904         }
1905
1906 #ifdef __native_client_codegen__
1907         if (g_getenv ("MONO_NACL_ALIGN_MASK_OFF"))
1908         {
1909                 nacl_align_byte = -1; /* 0xff */
1910         }
1911         if (!nacl_null_checks_off) {
1912                 MonoDebugOptions *opt = mini_get_debug_options ();
1913                 opt->explicit_null_checks = TRUE;
1914         }
1915 #endif
1916
1917         if (!argv [i]) {
1918                 mini_usage ();
1919                 return 1;
1920         }
1921
1922 #if !defined(HOST_WIN32) && defined(HAVE_UNISTD_H)
1923         /*
1924          * If we are not embedded, use the mono runtime executable to run managed exe's.
1925          */
1926         {
1927                 char *runtime_path;
1928
1929                 runtime_path = wapi_process_get_path (getpid ());
1930                 if (runtime_path) {
1931                         wapi_process_set_cli_launcher (runtime_path);
1932                         g_free (runtime_path);
1933                 }
1934         }
1935 #endif
1936
1937         if (g_getenv ("MONO_XDEBUG"))
1938                 enable_debugging = TRUE;
1939
1940 #ifdef MONO_CROSS_COMPILE
1941        if (!mono_compile_aot) {
1942                    fprintf (stderr, "This mono runtime is compiled for cross-compiling. Only the --aot option is supported.\n");
1943                    exit (1);
1944        }
1945 #if SIZEOF_VOID_P == 8 && (defined(TARGET_ARM) || defined(TARGET_X86))
1946        fprintf (stderr, "Can't cross-compile on 64-bit platforms to 32-bit architecture.\n");
1947        exit (1);
1948 #elif SIZEOF_VOID_P == 4 && (defined(TARGET_ARM64) || defined(TARGET_AMD64))
1949        fprintf (stderr, "Can't cross-compile on 32-bit platforms to 64-bit architecture.\n");
1950        exit (1);
1951 #endif
1952 #endif
1953
1954         if (mono_compile_aot || action == DO_EXEC || action == DO_DEBUGGER) {
1955                 g_set_prgname (argv[i]);
1956         }
1957
1958         mono_counters_init ();
1959
1960         /* Set rootdir before loading config */
1961         mono_set_rootdir ();
1962
1963         if (enable_profile)
1964                 mono_profiler_load (profile_options);
1965
1966         mono_attach_parse_options (attach_options);
1967
1968         if (trace_options != NULL){
1969                 /* 
1970                  * Need to call this before mini_init () so we can trace methods 
1971                  * compiled there too.
1972                  */
1973                 mono_jit_trace_calls = mono_trace_parse_options (trace_options);
1974                 if (mono_jit_trace_calls == NULL)
1975                         exit (1);
1976         }
1977
1978 #ifdef DISABLE_JIT
1979         if (!mono_aot_only) {
1980                 fprintf (stderr, "This runtime has been configured with --enable-minimal=jit, so the --full-aot command line option is required.\n");
1981                 exit (1);
1982         }
1983 #endif
1984
1985         if (action == DO_DEBUGGER) {
1986                 enable_debugging = TRUE;
1987                 g_print ("The Mono Debugger is no longer supported.\n");
1988                 return 1;
1989         } else if (enable_debugging)
1990                 mono_debug_init (MONO_DEBUG_FORMAT_MONO);
1991
1992 #ifdef HOST_WIN32
1993         if (mixed_mode)
1994                 mono_load_coree (argv [i]);
1995 #endif
1996
1997         /* Parse gac loading options before loading assemblies. */
1998         if (mono_compile_aot || action == DO_EXEC || action == DO_DEBUGGER) {
1999                 mono_config_parse (config_file);
2000         }
2001
2002         mono_set_defaults (mini_verbose, opt);
2003         domain = mini_init (argv [i], forced_version);
2004
2005         mono_gc_set_stack_end (&domain);
2006
2007         if (agents) {
2008                 int i;
2009
2010                 for (i = 0; i < agents->len; ++i) {
2011                         int res = load_agent (domain, (char*)g_ptr_array_index (agents, i));
2012                         if (res) {
2013                                 g_ptr_array_free (agents, TRUE);
2014                                 mini_cleanup (domain);
2015                                 return 1;
2016                         }
2017                 }
2018
2019                 g_ptr_array_free (agents, TRUE);
2020         }
2021         
2022         switch (action) {
2023         case DO_SINGLE_METHOD_REGRESSION:
2024                 mono_do_single_method_regression = TRUE;
2025         case DO_REGRESSION:
2026                 if (mini_regression_list (mini_verbose, argc -i, argv + i)) {
2027                         g_print ("Regression ERRORS!\n");
2028                         mini_cleanup (domain);
2029                         return 1;
2030                 }
2031                 mini_cleanup (domain);
2032                 return 0;
2033         case DO_BENCH:
2034                 if (argc - i != 1 || mname == NULL) {
2035                         g_print ("Usage: mini --ncompile num --compile method assembly\n");
2036                         mini_cleanup (domain);
2037                         return 1;
2038                 }
2039                 aname = argv [i];
2040                 break;
2041         case DO_COMPILE:
2042                 if (argc - i != 1) {
2043                         mini_usage ();
2044                         mini_cleanup (domain);
2045                         return 1;
2046                 }
2047                 aname = argv [i];
2048                 break;
2049         case DO_DRAW:
2050                 if (argc - i != 1 || mname == NULL) {
2051                         mini_usage ();
2052                         mini_cleanup (domain);
2053                         return 1;
2054                 }
2055                 aname = argv [i];
2056                 break;
2057         default:
2058                 if (argc - i < 1) {
2059                         mini_usage ();
2060                         mini_cleanup (domain);
2061                         return 1;
2062                 }
2063                 aname = argv [i];
2064                 break;
2065         }
2066
2067 #ifdef MONO_JIT_INFO_TABLE_TEST
2068         if (test_jit_info_table)
2069                 jit_info_table_test (domain);
2070 #endif
2071
2072         assembly = mono_assembly_open (aname, &open_status);
2073         if (!assembly) {
2074                 fprintf (stderr, "Cannot open assembly '%s': %s.\n", aname, mono_image_strerror (open_status));
2075                 mini_cleanup (domain);
2076                 return 2;
2077         }
2078
2079         if (trace_options != NULL)
2080                 mono_trace_set_assembly (assembly);
2081
2082         if (mono_compile_aot || action == DO_EXEC) {
2083                 const char *error;
2084
2085                 //mono_set_rootdir ();
2086
2087                 error = mono_check_corlib_version ();
2088                 if (error) {
2089                         fprintf (stderr, "Corlib not in sync with this runtime: %s\n", error);
2090                         fprintf (stderr, "Loaded from: %s\n",
2091                                 mono_defaults.corlib? mono_image_get_filename (mono_defaults.corlib): "unknown");
2092                         fprintf (stderr, "Download a newer corlib or a newer runtime at http://www.mono-project.com/download.\n");
2093                         exit (1);
2094                 }
2095
2096 #ifdef HOST_WIN32
2097                 /* Detach console when executing IMAGE_SUBSYSTEM_WINDOWS_GUI on win32 */
2098                 if (!enable_debugging && !mono_compile_aot && ((MonoCLIImageInfo*)(mono_assembly_get_image (assembly)->image_info))->cli_header.nt.pe_subsys_required == IMAGE_SUBSYSTEM_WINDOWS_GUI)
2099                         FreeConsole ();
2100 #endif
2101
2102                 main_args.domain = domain;
2103                 main_args.file = aname;         
2104                 main_args.argc = argc - i;
2105                 main_args.argv = argv + i;
2106                 main_args.opts = opt;
2107                 main_args.aot_options = aot_options;
2108 #if RUN_IN_SUBTHREAD
2109                 mono_runtime_exec_managed_code (domain, main_thread_handler, &main_args);
2110 #else
2111                 main_thread_handler (&main_args);
2112                 mono_thread_manage ();
2113 #endif
2114
2115                 mini_cleanup (domain);
2116
2117                 /* Look up return value from System.Environment.ExitCode */
2118                 i = mono_environment_exitcode_get ();
2119                 return i;
2120         } else if (action == DO_COMPILE) {
2121                 compile_all_methods (assembly, mini_verbose, opt, recompilation_times);
2122                 mini_cleanup (domain);
2123                 return 0;
2124         } else if (action == DO_DEBUGGER) {
2125                 return 1;
2126         }
2127         desc = mono_method_desc_new (mname, 0);
2128         if (!desc) {
2129                 g_print ("Invalid method name %s\n", mname);
2130                 mini_cleanup (domain);
2131                 return 3;
2132         }
2133         method = mono_method_desc_search_in_image (desc, mono_assembly_get_image (assembly));
2134         if (!method) {
2135                 g_print ("Cannot find method %s\n", mname);
2136                 mini_cleanup (domain);
2137                 return 3;
2138         }
2139
2140 #ifndef DISABLE_JIT
2141         if (action == DO_DRAW) {
2142                 int part = 0;
2143
2144                 switch (mono_graph_options) {
2145                 case MONO_GRAPH_DTREE:
2146                         part = 1;
2147                         opt |= MONO_OPT_LOOP;
2148                         break;
2149                 case MONO_GRAPH_CFG_CODE:
2150                         part = 1;
2151                         break;
2152                 case MONO_GRAPH_CFG_SSA:
2153                         part = 2;
2154                         break;
2155                 case MONO_GRAPH_CFG_OPTCODE:
2156                         part = 3;
2157                         break;
2158                 default:
2159                         break;
2160                 }
2161
2162                 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
2163                         (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
2164                         MonoMethod *nm;
2165                         nm = mono_marshal_get_native_wrapper (method, TRUE, FALSE);
2166                         cfg = mini_method_compile (nm, opt, mono_get_root_domain (), (JitFlags)0, part, -1);
2167                 }
2168                 else
2169                         cfg = mini_method_compile (method, opt, mono_get_root_domain (), (JitFlags)0, part, -1);
2170                 if ((mono_graph_options & MONO_GRAPH_CFG_SSA) && !(cfg->comp_done & MONO_COMP_SSA)) {
2171                         g_warning ("no SSA info available (use -O=deadce)");
2172                         return 1;
2173                 }
2174                 mono_draw_graph (cfg, mono_graph_options);
2175                 mono_destroy_compile (cfg);
2176
2177         } else if (action == DO_BENCH) {
2178                 if (mini_stats_fd) {
2179                         const char *n;
2180                         double no_opt_time = 0.0;
2181                         GTimer *timer = g_timer_new ();
2182                         fprintf (mini_stats_fd, "$stattitle = \'Compilations times for %s\';\n", 
2183                                  mono_method_full_name (method, TRUE));
2184                         fprintf (mini_stats_fd, "@data = (\n");
2185                         fprintf (mini_stats_fd, "[");
2186                         for (i = 0; i < G_N_ELEMENTS (opt_sets); i++) {
2187                                 opt = opt_sets [i];
2188                                 n = mono_opt_descr (opt);
2189                                 if (!n [0])
2190                                         n = "none";
2191                                 fprintf (mini_stats_fd, "\"%s\",", n);
2192                         }
2193                         fprintf (mini_stats_fd, "],\n[");
2194
2195                         for (i = 0; i < G_N_ELEMENTS (opt_sets); i++) {
2196                                 int j;
2197                                 double elapsed;
2198                                 opt = opt_sets [i];
2199                                 g_timer_start (timer);
2200                                 for (j = 0; j < count; ++j) {
2201                                         cfg = mini_method_compile (method, opt, mono_get_root_domain (), (JitFlags)0, 0, -1);
2202                                         mono_destroy_compile (cfg);
2203                                 }
2204                                 g_timer_stop (timer);
2205                                 elapsed = g_timer_elapsed (timer, NULL);
2206                                 if (!opt)
2207                                         no_opt_time = elapsed;
2208                                 fprintf (mini_stats_fd, "%f, ", elapsed);
2209                         }
2210                         fprintf (mini_stats_fd, "]");
2211                         if (no_opt_time > 0.0) {
2212                                 fprintf (mini_stats_fd, ", \n[");
2213                                 for (i = 0; i < G_N_ELEMENTS (opt_sets); i++) 
2214                                         fprintf (mini_stats_fd, "%f,", no_opt_time);
2215                                 fprintf (mini_stats_fd, "]");
2216                         }
2217                         fprintf (mini_stats_fd, ");\n");
2218                 } else {
2219                         for (i = 0; i < count; ++i) {
2220                                 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
2221                                         (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
2222                                         method = mono_marshal_get_native_wrapper (method, TRUE, FALSE);
2223
2224                                 cfg = mini_method_compile (method, opt, mono_get_root_domain (), (JitFlags)0, 0, -1);
2225                                 mono_destroy_compile (cfg);
2226                         }
2227                 }
2228         } else {
2229                 cfg = mini_method_compile (method, opt, mono_get_root_domain (), (JitFlags)0, 0, -1);
2230                 mono_destroy_compile (cfg);
2231         }
2232 #endif
2233
2234         mini_cleanup (domain);
2235         return 0;
2236 }
2237
2238 MonoDomain * 
2239 mono_jit_init (const char *file)
2240 {
2241         return mini_init (file, NULL);
2242 }
2243
2244 /**
2245  * mono_jit_init_version:
2246  * @domain_name: the name of the root domain
2247  * @runtime_version: the version of the runtime to load
2248  *
2249  * Use this version when you want to force a particular runtime
2250  * version to be used.  By default Mono will pick the runtime that is
2251  * referenced by the initial assembly (specified in @file), this
2252  * routine allows programmers to specify the actual runtime to be used
2253  * as the initial runtime is inherited by all future assemblies loaded
2254  * (since Mono does not support having more than one mscorlib runtime
2255  * loaded at once).
2256  *
2257  * The @runtime_version can be one of these strings: "v4.0.30319" for
2258  * desktop, "mobile" for mobile or "moonlight" for Silverlight compat.
2259  * If an unrecognized string is input, the vm will default to desktop.
2260  *
2261  * Returns: the MonoDomain representing the domain where the assembly
2262  * was loaded.
2263  */
2264 MonoDomain * 
2265 mono_jit_init_version (const char *domain_name, const char *runtime_version)
2266 {
2267         return mini_init (domain_name, runtime_version);
2268 }
2269
2270 void        
2271 mono_jit_cleanup (MonoDomain *domain)
2272 {
2273         mono_thread_manage ();
2274
2275         mini_cleanup (domain);
2276 }
2277
2278 void
2279 mono_jit_set_aot_only (gboolean val)
2280 {
2281         mono_aot_only = val;
2282 }
2283
2284 void
2285 mono_jit_set_aot_mode (MonoAotMode mode)
2286 {
2287         mono_aot_mode = mode;
2288         if (mono_aot_mode == MONO_AOT_MODE_LLVMONLY) {
2289                 mono_aot_only = TRUE;
2290                 mono_llvm_only = TRUE;
2291         }
2292 }
2293
2294 /**
2295  * mono_jit_set_trace_options:
2296  * @options: string representing the trace options
2297  *
2298  * Set the options of the tracing engine. This function can be called before initializing
2299  * the mono runtime. See the --trace mono(1) manpage for the options format.
2300  *
2301  * Returns: #TRUE if the options where parsed and set correctly, #FALSE otherwise.
2302  */
2303 gboolean
2304 mono_jit_set_trace_options (const char* options)
2305 {
2306         MonoTraceSpec *trace_opt = mono_trace_parse_options (options);
2307         if (trace_opt == NULL)
2308                 return FALSE;
2309         mono_jit_trace_calls = trace_opt;
2310         return TRUE;
2311 }
2312
2313 /**
2314  * mono_set_signal_chaining:
2315  *
2316  *   Enable/disable signal chaining. This should be called before mono_jit_init ().
2317  * If signal chaining is enabled, the runtime saves the original signal handlers before
2318  * installing its own handlers, and calls the original ones in the following cases:
2319  * - a SIGSEGV/SIGABRT signal received while executing native (i.e. not JITted) code.
2320  * - SIGPROF
2321  * - SIGFPE
2322  * - SIGQUIT
2323  * - SIGUSR2
2324  * Signal chaining only works on POSIX platforms.
2325  */
2326 void
2327 mono_set_signal_chaining (gboolean chain_signals)
2328 {
2329         mono_do_signal_chaining = chain_signals;
2330 }
2331
2332 /**
2333  * mono_set_crash_chaining:
2334  *
2335  * Enable/disable crash chaining due to signals. When a fatal signal is delivered and
2336  * Mono doesn't know how to handle it, it will invoke the crash handler. If chrash chaining
2337  * is enabled, it will first print its crash information and then try to chain with the native handler.
2338  */
2339 void
2340 mono_set_crash_chaining (gboolean chain_crashes)
2341 {
2342         mono_do_crash_chaining = chain_crashes;
2343 }
2344
2345 void
2346 mono_parse_env_options (int *ref_argc, char **ref_argv [])
2347 {
2348         int argc = *ref_argc;
2349         char **argv = *ref_argv;
2350
2351         const char *env_options = g_getenv ("MONO_ENV_OPTIONS");
2352         if (env_options != NULL){
2353                 GPtrArray *array = g_ptr_array_new ();
2354                 GString *buffer = g_string_new ("");
2355                 const char *p;
2356                 unsigned i;
2357                 gboolean in_quotes = FALSE;
2358                 char quote_char = '\0';
2359
2360                 for (p = env_options; *p; p++){
2361                         switch (*p){
2362                         case ' ': case '\t':
2363                                 if (!in_quotes) {
2364                                         if (buffer->len != 0){
2365                                                 g_ptr_array_add (array, g_strdup (buffer->str));
2366                                                 g_string_truncate (buffer, 0);
2367                                         }
2368                                 } else {
2369                                         g_string_append_c (buffer, *p);
2370                                 }
2371                                 break;
2372                         case '\\':
2373                                 if (p [1]){
2374                                         g_string_append_c (buffer, p [1]);
2375                                         p++;
2376                                 }
2377                                 break;
2378                         case '\'':
2379                         case '"':
2380                                 if (in_quotes) {
2381                                         if (quote_char == *p)
2382                                                 in_quotes = FALSE;
2383                                         else
2384                                                 g_string_append_c (buffer, *p);
2385                                 } else {
2386                                         in_quotes = TRUE;
2387                                         quote_char = *p;
2388                                 }
2389                                 break;
2390                         default:
2391                                 g_string_append_c (buffer, *p);
2392                                 break;
2393                         }
2394                 }
2395                 if (in_quotes) {
2396                         fprintf (stderr, "Unmatched quotes in value of MONO_ENV_OPTIONS: [%s]\n", env_options);
2397                         exit (1);
2398                 }
2399                         
2400                 if (buffer->len != 0)
2401                         g_ptr_array_add (array, g_strdup (buffer->str));
2402                 g_string_free (buffer, TRUE);
2403
2404                 if (array->len > 0){
2405                         int new_argc = array->len + argc;
2406                         char **new_argv = g_new (char *, new_argc + 1);
2407                         int j;
2408
2409                         new_argv [0] = argv [0];
2410                         
2411                         /* First the environment variable settings, to allow the command line options to override */
2412                         for (i = 0; i < array->len; i++)
2413                                 new_argv [i+1] = (char *)g_ptr_array_index (array, i);
2414                         i++;
2415                         for (j = 1; j < argc; j++)
2416                                 new_argv [i++] = argv [j];
2417                         new_argv [i] = NULL;
2418
2419                         *ref_argc = new_argc;
2420                         *ref_argv = new_argv;
2421                 }
2422                 g_ptr_array_free (array, TRUE);
2423         }
2424 }