2003-04-23 Martin Baulig <martin@ximian.com>
[mono.git] / mono / jit / mono.c
1 /*
2  * mono.c: Main driver for the Mono JIT engine
3  *
4  * Author:
5  *   Dietmar Maurer (dietmar@ximian.com)
6  *
7  * (C) 2001, 2002 Ximian, Inc (http://www.ximian.com)
8  */
9 #include "jit.h"
10 #include "regset.h"
11 #include "codegen.h"
12 #include "debug.h"
13 #include "mono/metadata/debug-helpers.h"
14 #include "mono/metadata/verify.h"
15 #include "mono/metadata/profiler.h"
16 #include "mono/metadata/threadpool.h"
17 #include "mono/metadata/mono-config.h"
18 #include <mono/metadata/profiler-private.h>
19 #include <mono/metadata/environment.h>
20 #include <mono/metadata/mono-debug.h>
21 #include <mono/metadata/mono-debug-debugger.h>
22 #include <mono/os/util.h>
23 #include <locale.h>
24
25 static MonoClass *
26 find_class_in_assembly (MonoAssembly *assembly, const char *namespace, const char *name)
27 {
28         MonoAssembly **ptr;
29         MonoClass *class;
30
31         class = mono_class_from_name (assembly->image, namespace, name);
32         if (class)
33                 return class;
34
35         for (ptr = assembly->image->references; ptr && *ptr; ptr++) {
36                 class = find_class_in_assembly (*ptr, namespace, name);
37                 if (class)
38                         return class;
39         }
40
41         return NULL;
42 }
43
44 static MonoMethod *
45 find_method_in_assembly (MonoAssembly *assembly, MonoMethodDesc *mdesc)
46 {
47         MonoAssembly **ptr;
48         MonoMethod *method;
49
50         method = mono_method_desc_search_in_image (mdesc, assembly->image);
51         if (method)
52                 return method;
53
54         for (ptr = assembly->image->references; ptr && *ptr; ptr++) {
55                 method = find_method_in_assembly (*ptr, mdesc);
56                 if (method)
57                         return method;
58         }
59
60         return NULL;
61 }
62
63 /**
64  * mono_jit_compile_class:
65  * @assembly: Lookup things in this assembly
66  * @compile_class: Name of the image/class/method to compile
67  * @compile_times: Compile it that many times
68  * @verbose: If true, print debugging information on stdout.
69  *
70  * JIT compilation of the image/class/method.
71  *
72  * @compile_class can be one of:
73  *
74  * - an image name (`@corlib')
75  * - a class name (`System.Int32')
76  * - a method name (`System.Int32:Parse')
77  */
78 void
79 mono_jit_compile_class (MonoAssembly *assembly, char *compile_class,
80                         int compile_times, int verbose)
81 {
82         const char *cmethod = strrchr (compile_class, ':');
83         char *cname;
84         char *code;
85         int i, j;
86         MonoClass *class;
87         MonoDomain *domain = mono_domain_get ();
88
89         if (compile_class [0] == '@') {
90                 MonoImage *image = mono_image_loaded (compile_class + 1);
91                 if (!image)
92                         g_error ("Cannot find image %s", compile_class + 1);
93                 if (verbose)
94                         g_print ("Compiling image %s\n", image->name);
95                 for (j = 0; j < compile_times; ++j)
96                         mono_jit_compile_image (image, verbose);
97         } else if (cmethod) {
98                 MonoMethodDesc *mdesc;
99                 MonoMethod *m;
100                 mdesc = mono_method_desc_new (compile_class, FALSE);
101                 if (!mdesc)
102                         g_error ("Invalid method name '%s'", compile_class);
103                 m = find_method_in_assembly (assembly, mdesc);
104                 if (!m)
105                         g_error ("Cannot find method '%s'", compile_class);
106                 for (j = 0; j < compile_times; ++j) {
107                         code = mono_compile_method (m);
108                         // g_free (code);
109                         g_hash_table_remove (domain->jit_code_hash, m);
110                 }
111         } else {
112                 cname = strrchr (compile_class, '.');
113                 if (cname)
114                         *cname++ = 0;
115                 else {
116                         cname = compile_class;
117                         compile_class = (char *)"";
118                 }
119                 class = find_class_in_assembly (assembly, compile_class, cname);
120                 if (!class)
121                         g_error ("Cannot find class %s.%s", compile_class, cname);
122                 mono_class_init (class);
123                 for (j = 0; j < compile_times; ++j) {
124                         for (i = 0; i < class->method.count; ++i) {
125                                 if (class->methods [i]->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)
126                                         continue;
127                                 if (class->methods [i]->flags & METHOD_ATTRIBUTE_ABSTRACT)
128                                         continue;
129                                 if (verbose)
130                                         g_print ("Compiling: %s.%s:%s\n",
131                                                  compile_class, cname, class->methods [i]->name);
132                                 code = mono_compile_method (class->methods [i]);
133                                 g_hash_table_remove (domain->jit_code_hash, class->methods [i]);
134                                 // g_free (code);
135                         }
136                 }
137         }
138 }
139
140 static void
141 usage (char *name)
142 {
143         fprintf (stderr,
144                  "mono %s, the Mono ECMA CLI JIT Compiler, (C) 2001, 2002 Ximian, Inc.\n\n"
145                  "Usage is: %s [options] executable args...\n\n",  VERSION, name);
146         fprintf (stderr,
147                  "Runtime Debugging:\n"
148                  "    -d                 debug the jit, show disassembler output.\n"
149                  "    --dump-asm         dumps the assembly code generated\n"
150                  "    --dump-forest      dumps the reconstructed forest\n"
151                  "    --print-vtable     print the VTable of all used classes\n"
152                  "    --stats            print statistics about the jit operations\n"
153                  "    --trace            printf function call trace\n"
154                  "    --compile NAME     compile NAME, then exit.\n"
155                  "                       NAME is in one of the following formats:\n"
156                  "                         namespace.name          compile the given class\n"
157                  "                         namespace.name:method   compile the given method\n"
158                  "                         @imagename              compile the given image\n"
159                  "    --ncompile NUM     compile methods NUM times (default: 1000)\n"
160                  "    --noboundcheck     Disables bound checks\n"
161                  "\n"
162                  "Development:\n"
163                  "    --debug            enable debugging support.\n"
164                  "    --profile          record and dump profile info\n"
165                  "    --breakonex        set a breakpoint for unhandled exception\n"
166                  "    --break NAME       insert a breakpoint at the start of method NAME\n"
167                  "                       (NAME is in `namespace.name:methodname' format\n"
168                  "                       or `Main' to break on the application's main method)\n"
169                  "    --precompile name  precompile NAME before executing the main application:\n"
170                  "                       NAME is in one of the following formats:\n"
171                  "                         namespace.name          compile the given class\n"
172                  "                         namespace.name:method   compile the given method\n"
173                  "                         @imagename              compile the given image\n"
174                  "\n"
175                  "Runtime:\n"
176                  "    --config filename  Load specified config file instead of the default.\n"
177                  "    --fast-iconv       Use fast floating point integer conversion\n"
178                  "    --noinline         Disable code inliner\n"
179                  "    --nointrinsic      Disable memcopy inliner\n"
180                  "    --nols             disable linear scan register allocation\n"
181                  "    --share-code       force jit to produce shared code\n"
182                  "    --workers n        maximum number of worker threads\n"
183                 );
184         exit (1);
185 }
186
187 typedef struct 
188 {
189         MonoDomain *domain;
190         char *file;
191         gboolean testjit;
192         gboolean enable_debugging;
193         char *compile_class;
194         int compile_times;
195         GList *precompile_classes;
196         int verbose;
197         int break_on_main;
198         int argc;
199         char **argv;
200 } MainThreadArgs;
201
202 static void main_thread_handler (gpointer user_data)
203 {
204         MainThreadArgs *main_args=(MainThreadArgs *)user_data;
205         MonoAssembly *assembly;
206
207         if (main_args->enable_debugging)
208                 mono_debug_init (MONO_DEBUG_FORMAT_MONO);
209
210         assembly = mono_domain_assembly_open (main_args->domain,
211                                               main_args->file);
212         if (!assembly){
213                 fprintf (stderr, "Can not open image %s\n", main_args->file);
214                 exit (1);
215         }
216
217         if (main_args->enable_debugging)
218                 mono_debug_init_2 (assembly);
219
220         if (main_args->testjit) {
221                 mono_jit_compile_image (assembly->image, TRUE);
222         } else if (main_args->compile_class) {
223                 mono_jit_compile_class (assembly, main_args->compile_class, main_args->compile_times, TRUE);
224         } else {
225                 GList *tmp;
226
227                 for (tmp = main_args->precompile_classes; tmp; tmp = tmp->next)
228                         mono_jit_compile_class (assembly, tmp->data, 1,
229                                                 main_args->verbose);
230
231                 if (main_args->break_on_main) {
232                         MonoImage *image = assembly->image;
233                         MonoMethodDesc *desc;
234                         MonoMethod *method;
235
236                         method = mono_get_method (image, mono_image_get_entry_point (image), NULL);
237                         desc = mono_method_desc_from_method (method);
238                         mono_debugger_insert_breakpoint_full (desc, FALSE);
239                 }
240
241                 mono_jit_exec (main_args->domain, assembly, main_args->argc,
242                                main_args->argv);
243         }
244 }
245
246 int 
247 main (int argc, char *argv [])
248 {
249         MonoDomain *domain;
250         int retval = 0, i;
251         int compile_times = 1000;
252         char *compile_class = NULL;
253         gboolean enable_debugging = FALSE;
254         char *file, *error, *config_file = NULL;
255         gboolean testjit = FALSE;
256         int verbose = FALSE;
257         GList *precompile_classes = NULL;
258         int break_on_main = FALSE;
259         MainThreadArgs main_args;
260         
261         setlocale(LC_ALL, "");
262         g_log_set_always_fatal (G_LOG_LEVEL_ERROR);
263         g_log_set_fatal_mask (G_LOG_DOMAIN, G_LOG_LEVEL_ERROR);
264         
265         if (argc < 2)
266                 usage (argv [0]);
267
268         for (i = 1; i < argc && argv [i][0] == '-'; i++){
269                 if (strcmp (argv [i], "--help") == 0) {
270                         usage (argv [0]);
271                 } else if (strcmp (argv [i], "-d") == 0) {
272                         testjit = TRUE;
273                         mono_jit_dump_asm = TRUE;
274                         mono_jit_dump_forest = TRUE;
275                 } else if (strcmp (argv [i], "--dump-asm") == 0)
276                         mono_jit_dump_asm = TRUE;
277                 else if (strcmp (argv [i], "--dump-forest") == 0)
278                         mono_jit_dump_forest = TRUE;
279                 else if (strcmp (argv [i], "--trace") == 0)
280                         mono_jit_trace_calls = TRUE;
281                 else if (strcmp (argv [i], "--share-code") == 0)
282                         mono_jit_share_code = TRUE;
283                 else if (strcmp (argv [i], "--noinline") == 0)
284                         mono_jit_inline_code = FALSE;
285                 else if (strcmp (argv [i], "--nointrinsic") == 0)
286                         mono_inline_memcpy = FALSE;
287                 else if (strcmp (argv [i], "--noboundcheck") == 0)
288                         mono_jit_boundcheck = FALSE;
289                 else if (strcmp (argv [i], "--nols") == 0)
290                         mono_use_linear_scan = FALSE;
291                 else if (strcmp (argv [i], "--breakonex") == 0)
292                         mono_break_on_exc = TRUE;
293                 else if (strcmp (argv [i], "--print-vtable") == 0)
294                         mono_print_vtable = TRUE;
295                 else if (strcmp (argv [i], "--break") == 0) {
296                         if (!strcmp (argv [i+1], "Main")) {
297                                 break_on_main = TRUE;
298                                 i++;
299                         } else {
300                                 if (!mono_debugger_insert_breakpoint (argv [++i], FALSE))
301                                         g_error ("Invalid method name '%s'", argv [i]);
302                         }
303                 } else if (strcmp (argv [i], "--count") == 0) {
304                         compile_times = atoi (argv [++i]);
305                 } else if (strcmp (argv [i], "--config") == 0) {
306                         config_file = argv [++i];
307                 } else if (strcmp (argv [i], "--workers") == 0) {
308                         mono_worker_threads = atoi (argv [++i]);
309                         if (mono_worker_threads < 1)
310                                 mono_worker_threads = 1;
311                 } else if (strcmp (argv [i], "--profile") == 0) {
312                         mono_jit_profile = TRUE;
313                         mono_profiler_install_simple ();
314                 } else if (strcmp (argv [i], "--compile") == 0) {
315                         compile_class = argv [++i];
316                 } else if (strcmp (argv [i], "--ncompile") == 0) {
317                         compile_times = atoi (argv [++i]);
318                 } else if (strcmp (argv [i], "--stats") == 0) {
319                         memset (&mono_jit_stats, 0, sizeof (MonoJitStats));
320                         mono_jit_stats.enabled = TRUE;
321                 } else if (strcmp (argv [i], "--debug") == 0) {
322                         enable_debugging = TRUE;
323                 } else if (strcmp (argv [i], "--precompile") == 0) {
324                         precompile_classes = g_list_append (precompile_classes, argv [++i]);
325                 } else if (strcmp (argv [i], "--verbose") == 0) {
326                         verbose = TRUE;;
327                 } else if (strcmp (argv [i], "--fast-iconv") == 0) {
328                         mono_use_fast_iconv = TRUE;
329                 } else
330                         usage (argv [0]);
331         }
332         
333         file = argv [i];
334
335         if (!file)
336                 usage (argv [0]);
337
338         g_set_prgname (file);
339         mono_config_parse (config_file);
340         mono_set_rootdir ();
341
342         domain = mono_jit_init (file);
343
344         error = mono_verify_corlib ();
345         if (error) {
346                 fprintf (stderr, "Corlib not in sync with this runtime: %s\n", error);
347                 exit (1);
348         }
349         
350         main_args.domain=domain;
351         main_args.file=file;
352         main_args.testjit=testjit;
353         main_args.enable_debugging=enable_debugging;
354         main_args.compile_class=compile_class;
355         main_args.compile_times=compile_times;
356         main_args.precompile_classes=precompile_classes;
357         main_args.verbose=verbose;
358         main_args.break_on_main=break_on_main;
359         main_args.argc=argc-i;
360         main_args.argv=argv+i;
361         
362         mono_runtime_exec_managed_code (domain, main_thread_handler,
363                                         &main_args);
364
365         mono_profiler_shutdown ();
366         mono_jit_cleanup (domain);
367
368         /* Look up return value from System.Environment.ExitCode */
369         retval=mono_environment_exitcode_get ();
370         
371         return retval;
372 }