2 * aot.c: mono Ahead of Time compiler
5 * Dietmar Maurer (dietmar@ximian.com)
7 * (C) 2002 Ximian, Inc.
11 #include <sys/types.h>
14 #ifndef PLATFORM_WIN32
20 #include <limits.h> /* for PAGESIZE */
25 #include <mono/metadata/tabledefs.h>
26 #include <mono/metadata/class.h>
27 #include <mono/metadata/object.h>
28 #include <mono/metadata/tokentype.h>
29 #include <mono/metadata/appdomain.h>
30 #include <mono/metadata/debug-helpers.h>
34 #define ENCODE_TYPE_POS(t,l) (((t) << 24) | (l))
35 #define DECODE_TYPE(v) ((v) >> 24)
36 #define DECODE_POS(v) ((v) & 0xffffff)
39 #define SHARED_EXT ".dll"
41 #define SHARED_EXT ".so"
45 decode_class_info (gpointer *data)
50 image = mono_image_loaded_by_guid ((char *)data [1]);
54 return mono_class_get (image, (guint32)data [0]);
56 klass = decode_class_info (data [3]);
57 return mono_array_class_get (klass, (guint32)data [2]);
64 mono_aot_get_method (MonoMethod *method)
66 MonoClass *klass = method->klass;
67 MonoAssembly *ass = klass->image->assembly;
68 MonoJumpInfo *patch_info = NULL;
69 GModule *module = ass->aot_module;
70 char *method_label, *info_label;
73 guint code_len, used_int_regs, used_strings;
82 g_assert (klass->inited);
84 method_label = g_strdup_printf ("method_%08X", method->token);
86 if (!g_module_symbol (module, method_label, (gpointer *)&code)) {
87 g_free (method_label);
91 info_label = g_strdup_printf ("%s_patch_info", method_label);
92 if (!g_module_symbol (module, info_label, (gpointer *)&info)) {
93 g_free (method_label);
98 //printf ("FOUND AOT compiled code for %s %p %p\n", mono_method_full_name (method, TRUE), code, info);
100 code_len = GPOINTER_TO_UINT (*((gpointer **)info));
102 used_int_regs = GPOINTER_TO_UINT (*((gpointer **)info));
104 used_strings = GPOINTER_TO_UINT (*((gpointer **)info));
107 for (i = 0; i < used_strings; i++) {
108 guint token = GPOINTER_TO_UINT (*((gpointer **)info));
110 mono_ldstr (mono_root_domain, klass->image, mono_metadata_token_index (token));
115 MonoMemPool *mp = mono_mempool_new ();
123 MonoJumpInfo *ji = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
124 gpointer *data = *((gpointer **)info);
126 ji->type = DECODE_TYPE (GPOINTER_TO_UINT (*info));
127 ji->ip.i = DECODE_POS (GPOINTER_TO_UINT (*info));
130 case MONO_PATCH_INFO_CLASS:
131 ji->data.klass = decode_class_info (data);
132 g_assert (ji->data.klass);
133 mono_class_init (ji->data.klass);
135 case MONO_PATCH_INFO_IMAGE:
136 ji->data.image = mono_image_loaded_by_guid ((char *)data);
137 g_assert (ji->data.image);
139 case MONO_PATCH_INFO_METHOD:
140 case MONO_PATCH_INFO_METHODCONST:
141 image = mono_image_loaded_by_guid ((char *)data [1]);
143 ji->data.method = mono_get_method (image, (guint32)data [0], NULL);
144 g_assert (ji->data.method);
145 mono_class_init (ji->data.method->klass);
147 case MONO_PATCH_INFO_FIELD:
148 image = mono_image_loaded_by_guid ((char *)data [1]);
150 ji->data.field = mono_field_from_token (image, (guint32)data [0], NULL);
151 mono_class_init (ji->data.field->parent);
152 g_assert (ji->data.field);
154 case MONO_PATCH_INFO_INTERNAL_METHOD:
155 ji->data.name = (char *)data;
156 g_assert (ji->data.name);
158 case MONO_PATCH_INFO_SWITCH:
159 ji->table_size = (int)data [0];
160 table = g_new (gpointer, ji->table_size);
161 ji->data.target = table;
162 for (i = 0; i < ji->table_size; i++) {
163 table [i] = data [i + 1];
166 case MONO_PATCH_INFO_R4:
167 case MONO_PATCH_INFO_R8:
168 ji->data.target = data;
171 g_warning ("unhandled type %d", ji->type);
172 g_assert_not_reached ();
176 ji->next = patch_info;
180 #ifndef PLATFORM_WIN32
181 /* disable write protection */
182 page_start = (char *) (((int) (code)) & ~ (PAGESIZE - 1));
183 pages = (code + code_len - page_start + PAGESIZE - 1) / PAGESIZE;
184 err = mprotect (page_start, pages * PAGESIZE, PROT_READ | PROT_WRITE | PROT_EXEC);
189 g_assert (VirtualProtect (code, code_len, PAGE_EXECUTE_READWRITE, &oldp) != 0);
193 mono_arch_patch_code (method, mono_root_domain, code, patch_info);
194 mono_mempool_destroy (mp);
198 g_free (method_label);
202 info = mono_mempool_alloc0 (mono_root_domain->mp, sizeof (MonoJitInfo));
203 info->code_size = code_len;
204 info->used_regs = used_int_regs;
205 info->method = method;
206 info->code_start = code;
207 mono_jit_info_table_add (mono_root_domain, info);
209 mono_jit_stats.methods_aot++;
216 write_data_symbol (FILE *fp, const char *name, guint8 *buf, int size, int align)
220 fprintf (fp, ".globl %s\n", name);
221 fprintf (fp, ".data\n\t.align %d\n", align);
222 fprintf (fp, "\t.type %s,@object\n", name);
223 fprintf (fp, "\t.size %s,%d\n", name, size);
224 fprintf (fp, "%s:\n", name);
225 for (i = 0; i < size; i++) {
226 fprintf (fp, ".byte %d\n", buf [i]);
233 write_string_symbol (FILE *fp, const char *name, char *value)
235 fprintf (fp, ".globl %s\n", name);
236 fprintf (fp, ".data\n");
237 fprintf (fp, "%s:\n", name);
238 fprintf (fp, "\t.string \"%s\"\n", value);
242 mono_get_field_token (MonoClassField *field)
244 MonoClass *klass = field->parent;
247 for (i = 0; i < klass->field.count; ++i) {
248 if (field == &klass->fields [i])
249 return MONO_TOKEN_FIELD_DEF | (klass->field.first + 1 + i);
252 g_assert_not_reached ();
257 cond_emit_image_label (FILE *tmpfp, GHashTable *image_hash, MonoImage *image)
261 if ((label = g_hash_table_lookup (image_hash, image)))
264 label = g_strdup_printf ("image_patch_info_%p", image);
265 fprintf (tmpfp, "%s:\n", label);
266 fprintf (tmpfp, "\t.string \"%s\"\n", image->guid);
268 g_hash_table_insert (image_hash, image, label);
274 cond_emit_icall_label (FILE *tmpfp, GHashTable *hash, const char *icall_name)
278 if ((label = g_hash_table_lookup (hash, icall_name)))
281 label = g_strdup_printf ("icall_patch_info_%s", icall_name);
282 fprintf (tmpfp, "%s:\n", label);
283 fprintf (tmpfp, "\t.string \"%s\"\n", icall_name);
285 g_hash_table_insert (hash, (gpointer)icall_name, label);
291 cond_emit_method_label (FILE *tmpfp, GHashTable *hash, MonoJumpInfo *patch_info)
293 MonoMethod *method = patch_info->data.method;
296 if ((l1 = g_hash_table_lookup (hash, method)))
299 l2 = cond_emit_image_label (tmpfp, hash, method->klass->image);
300 fprintf (tmpfp, "\t.align %d\n", sizeof (gpointer));
301 l1 = g_strdup_printf ("method_patch_info_%08x_%p", method->token, method);
302 fprintf (tmpfp, "%s:\n", l1);
303 fprintf (tmpfp, "\t.long 0x%08x\n", method->token);
304 g_assert (method->token);
305 fprintf (tmpfp, "\t.long %s\n", l2);
307 g_hash_table_insert (hash, method, l1);
313 cond_emit_klass_label (FILE *tmpfp, GHashTable *hash, MonoClass *klass)
315 char *l1, *l2, *el = NULL;
317 if ((l1 = g_hash_table_lookup (hash, klass)))
320 if (!klass->type_token) {
321 g_assert (klass->rank > 0);
322 el = cond_emit_klass_label (tmpfp, hash, klass->element_class);
325 l2 = cond_emit_image_label (tmpfp, hash, klass->image);
326 fprintf (tmpfp, "\t.align %d\n", sizeof (gpointer));
327 l1 = g_strdup_printf ("klass_patch_info_%08x_%p", klass->type_token, klass);
328 fprintf (tmpfp, "%s:\n", l1);
329 fprintf (tmpfp, "\t.long 0x%08x\n", klass->type_token);
330 fprintf (tmpfp, "\t.long %s\n", l2);
333 fprintf (tmpfp, "\t.long %d\n", klass->rank);
334 fprintf (tmpfp, "\t.long %s\n", el);
337 g_hash_table_insert (hash, klass, l1);
343 cond_emit_field_label (FILE *tmpfp, GHashTable *hash, MonoJumpInfo *patch_info)
345 MonoClassField *field = patch_info->data.field;
349 if ((l1 = g_hash_table_lookup (hash, field)))
352 l2 = cond_emit_image_label (tmpfp, hash, field->parent->image);
353 fprintf (tmpfp, "\t.align %d\n", sizeof (gpointer));
354 token = mono_get_field_token (field);
355 l1 = g_strdup_printf ("klass_patch_info_%08x_%p", token, field);
356 fprintf (tmpfp, "%s:\n", l1);
357 fprintf (tmpfp, "\t.long 0x%08x\n", token);
359 fprintf (tmpfp, "\t.long %s\n", l2);
361 g_hash_table_insert (hash, field, l1);
367 mono_compile_assembly (MonoAssembly *ass, guint32 opts)
370 MonoImage *image = ass->image;
373 char *com, *tmpfname;
376 guint8 *code, *mname;
377 int ccount = 0, mcount = 0, lmfcount = 0, ecount = 0, abscount = 0, wrappercount = 0, ocount = 0;
378 GHashTable *ref_hash;
379 int func_alignment = 16;
381 printf ("Mono AOT compiler - compiling assembly %s\n", image->name);
383 i = g_file_open_tmp ("mono_aot_XXXXXX", &tmpfname, NULL);
384 tmpfp = fdopen (i, "w+");
387 ref_hash = g_hash_table_new (NULL, NULL);
389 write_string_symbol (tmpfp, "mono_assembly_guid" , image->guid);
391 for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
392 MonoJumpInfo *patch_info;
394 guint32 token = MONO_TOKEN_METHOD_DEF | (i + 1);
395 method = mono_get_method (image, token, NULL);
397 /* fixme: maybe we can also precompile wrapper methods */
398 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
399 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
400 (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
401 (method->flags & METHOD_ATTRIBUTE_ABSTRACT)) {
402 //printf ("Skip (impossible): %s\n", mono_method_full_name (method, TRUE));
408 /* fixme: we need to patch the IP for the LMF in that case */
409 if (method->save_lmf) {
410 //printf ("Skip (needs lmf): %s\n", mono_method_full_name (method, TRUE));
415 /* fixme: add methods with exception tables */
416 if (((MonoMethodNormal *)method)->header->num_clauses) {
417 //printf ("Skip (exceptions): %s\n", mono_method_full_name (method, TRUE));
422 //printf ("START: %s\n", mono_method_full_name (method, TRUE));
423 //mono_compile_method (method);
425 cfg = mini_method_compile (method, opts, mono_root_domain, 0);
428 if (cfg->disable_aot) {
434 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
435 if (patch_info->type == MONO_PATCH_INFO_ABS) {
436 /* unable to handle this */
437 //printf ("Skip (abs addr): %s %d\n", mono_method_full_name (method, TRUE), patch_info->type);
449 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
450 if ((patch_info->type == MONO_PATCH_INFO_METHOD ||
451 patch_info->type == MONO_PATCH_INFO_METHODCONST) &&
452 patch_info->data.method->wrapper_type) {
453 /* unable to handle this */
454 //printf ("Skip (wrapper call): %s %d\n", mono_method_full_name (method, TRUE), patch_info->type);
465 //printf ("Compile: %s\n", mono_method_full_name (method, TRUE));
467 code = cfg->native_code;
469 fprintf (tmpfp, ".text\n");
470 mname = g_strdup_printf ("method_%08X", token);
471 fprintf (tmpfp, "\t.align %d\n", func_alignment);
472 fprintf (tmpfp, ".globl %s\n", mname);
473 fprintf (tmpfp, "\t.type %s,@function\n", mname);
474 fprintf (tmpfp, "%s:\n", mname);
476 for (j = 0; j < cfg->code_len; j++)
477 fprintf (tmpfp, ".byte %d\n", (unsigned int) code [j]);
479 fprintf (tmpfp, ".data\n");
482 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
483 switch (patch_info->type) {
484 case MONO_PATCH_INFO_LABEL:
485 case MONO_PATCH_INFO_BB:
486 /* relative jumps are no problem, there is no need to handle then here */
488 case MONO_PATCH_INFO_SWITCH: {
489 gpointer *table = (gpointer *)patch_info->data.target;
492 fprintf (tmpfp, "\t.align %d\n", sizeof (gpointer));
493 fprintf (tmpfp, "%s_patch_info_%d:\n", mname, j);
494 fprintf (tmpfp, "\t.long %d\n", patch_info->table_size);
496 for (k = 0; k < patch_info->table_size; k++) {
497 fprintf (tmpfp, "\t.long %d\n", (guint8 *)table [k] - code);
502 case MONO_PATCH_INFO_INTERNAL_METHOD:
503 patch_info->data.name = cond_emit_icall_label (tmpfp, ref_hash, patch_info->data.name);
506 case MONO_PATCH_INFO_METHODCONST:
507 case MONO_PATCH_INFO_METHOD:
508 patch_info->data.name = cond_emit_method_label (tmpfp, ref_hash, patch_info);
511 case MONO_PATCH_INFO_FIELD:
512 patch_info->data.name = cond_emit_field_label (tmpfp, ref_hash, patch_info);
515 case MONO_PATCH_INFO_CLASS:
516 patch_info->data.name = cond_emit_klass_label (tmpfp, ref_hash, patch_info->data.klass);
519 case MONO_PATCH_INFO_IMAGE:
520 patch_info->data.name = cond_emit_image_label (tmpfp, ref_hash, patch_info->data.image);
523 case MONO_PATCH_INFO_R4:
524 fprintf (tmpfp, "\t.align 8\n");
525 fprintf (tmpfp, "%s_patch_info_%d:\n", mname, j);
526 fprintf (tmpfp, "\t.long 0x%08x\n", *((guint32 *)patch_info->data.target));
530 case MONO_PATCH_INFO_R8:
531 fprintf (tmpfp, "\t.align 8\n");
532 fprintf (tmpfp, "%s_patch_info_%d:\n", mname, j);
533 fprintf (tmpfp, "\t.long 0x%08x\n", *((guint32 *)patch_info->data.target));
534 fprintf (tmpfp, "\t.long 0x%08x\n", *((guint32 *)patch_info->data.target + 1));
539 g_warning ("unable to handle jump info %d", patch_info->type);
540 g_assert_not_reached ();
544 fprintf (tmpfp, ".globl %s_patch_info\n", mname);
545 fprintf (tmpfp, "\t.align %d\n", sizeof (gpointer));
546 fprintf (tmpfp, "%s_patch_info:\n", mname);
548 fprintf (tmpfp, "\t.long %d\n", cfg->code_len);
549 fprintf (tmpfp, "\t.long %d\n", cfg->used_int_regs);
551 fprintf (tmpfp, "\t.long %d\n", g_list_length (cfg->ldstr_list));
552 for (l = cfg->ldstr_list; l; l = l->next) {
553 fprintf (tmpfp, "\t.long 0x%08x\n", l->data);
558 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
559 switch (patch_info->type) {
560 case MONO_PATCH_INFO_METHODCONST:
561 case MONO_PATCH_INFO_METHOD:
562 case MONO_PATCH_INFO_CLASS:
563 case MONO_PATCH_INFO_FIELD:
564 case MONO_PATCH_INFO_INTERNAL_METHOD:
565 case MONO_PATCH_INFO_IMAGE:
566 fprintf (tmpfp, "\t.long %s\n", patch_info->data.name);
567 fprintf (tmpfp, "\t.long 0x%08x\n", ENCODE_TYPE_POS (patch_info->type, patch_info->ip.i));
570 case MONO_PATCH_INFO_SWITCH:
571 case MONO_PATCH_INFO_R4:
572 case MONO_PATCH_INFO_R8:
573 fprintf (tmpfp, "\t.long %s_patch_info_%d\n", mname, j);
574 fprintf (tmpfp, "\t.long 0x%08x\n", ENCODE_TYPE_POS (patch_info->type, patch_info->ip.i));
577 case MONO_PATCH_INFO_LABEL:
578 case MONO_PATCH_INFO_BB:
581 g_warning ("unable to handle jump info %d", patch_info->type);
582 g_assert_not_reached ();
587 /* NULL terminated array */
588 fprintf (tmpfp, "\t.long 0\n");
590 /* fixme: save the rest of the required infos */
593 mono_destroy_compile (cfg);
600 com = g_strdup_printf ("as %s -o %s.o", tmpfname, tmpfname);
601 printf ("Executing the native assembler: %s\n", com);
604 com = g_strdup_printf ("ld -shared -o %s%s %s.o", image->name, SHARED_EXT, tmpfname);
605 printf ("Executing the native linker: %s\n", com);
608 com = g_strdup_printf ("%s.o", tmpfname);
611 /*com = g_strdup_printf ("strip --strip-unneeded %s%s", image->name, SHARED_EXT);
612 printf ("Stripping the binary: %s\n", com);
616 printf ("Compiled %d out of %d methods (%d%%)\n", ccount, mcount, (ccount*100)/mcount);
617 printf ("%d methods contain exception tables (%d%%)\n", ecount, (ecount*100)/mcount);
618 printf ("%d methods contain absolute addresses (%d%%)\n", abscount, (abscount*100)/mcount);
619 printf ("%d methods contain wrapper references (%d%%)\n", wrappercount, (wrappercount*100)/mcount);
620 printf ("%d methods contain lmf pointers (%d%%)\n", lmfcount, (lmfcount*100)/mcount);
621 printf ("%d methods have other problems (%d%%)\n", ocount, (ocount*100)/mcount);