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