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