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
18 #include <limits.h> /* for PAGESIZE */
23 #include <mono/metadata/tabledefs.h>
24 #include <mono/metadata/class.h>
25 #include <mono/metadata/object.h>
26 #include <mono/metadata/tokentype.h>
27 #include <mono/metadata/appdomain.h>
28 #include <mono/metadata/debug-helpers.h>
32 #define ENCODE_TYPE_POS(t,l) (((t) << 24) | (l))
33 #define DECODE_TYPE(v) ((v) >> 24)
34 #define DECODE_POS(v) ((v) & 0xffffff)
37 decode_class_info (gpointer *data)
42 image = mono_image_loaded_by_guid ((char *)data [1]);
46 return mono_class_get (image, (guint32)data [0]);
48 klass = decode_class_info (data [3]);
49 return mono_array_class_get (&klass->byval_arg, (guint32)data [2]);
56 mono_aot_get_method (MonoMethod *method)
58 MonoClass *klass = method->klass;
59 MonoAssembly *ass = klass->image->assembly;
60 MonoJumpInfo *patch_info = NULL;
61 GModule *module = ass->aot_module;
62 char *method_label, *info_label;
65 guint code_len, used_int_regs, used_strings;
74 g_assert (klass->inited);
76 method_label = g_strdup_printf ("method_%08X", method->token);
78 if (!g_module_symbol (module, method_label, (gpointer *)&code)) {
79 g_free (method_label);
83 info_label = g_strdup_printf ("%s_patch_info", method_label);
84 if (!g_module_symbol (module, info_label, (gpointer *)&info)) {
85 g_free (method_label);
90 //printf ("FOUND AOT compiled code for %s %p %p\n", mono_method_full_name (method, TRUE), code, info);
92 code_len = GPOINTER_TO_UINT (*((gpointer **)info));
94 used_int_regs = GPOINTER_TO_UINT (*((gpointer **)info));
96 used_strings = GPOINTER_TO_UINT (*((gpointer **)info));
99 for (i = 0; i < used_strings; i++) {
100 guint token = GPOINTER_TO_UINT (*((gpointer **)info));
102 mono_ldstr (mono_root_domain, klass->image, mono_metadata_token_index (token));
107 MonoMemPool *mp = mono_mempool_new ();
115 MonoJumpInfo *ji = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
116 gpointer *data = *((gpointer **)info);
118 ji->type = DECODE_TYPE (GPOINTER_TO_UINT (*info));
119 ji->ip.i = DECODE_POS (GPOINTER_TO_UINT (*info));
122 case MONO_PATCH_INFO_CLASS:
123 ji->data.klass = decode_class_info (data);
124 g_assert (ji->data.klass);
125 mono_class_init (ji->data.klass);
127 case MONO_PATCH_INFO_IMAGE:
128 ji->data.image = mono_image_loaded_by_guid ((char *)data);
129 g_assert (ji->data.image);
131 case MONO_PATCH_INFO_METHOD:
132 case MONO_PATCH_INFO_METHODCONST:
133 image = mono_image_loaded_by_guid ((char *)data [1]);
135 ji->data.method = mono_get_method (image, (guint32)data [0], NULL);
136 g_assert (ji->data.method);
137 mono_class_init (ji->data.method->klass);
139 case MONO_PATCH_INFO_FIELD:
140 image = mono_image_loaded_by_guid ((char *)data [1]);
142 ji->data.field = mono_field_from_token (image, (guint32)data [0], NULL);
143 mono_class_init (ji->data.field->parent);
144 g_assert (ji->data.field);
146 case MONO_PATCH_INFO_INTERNAL_METHOD:
147 ji->data.name = (char *)data;
148 g_assert (ji->data.name);
150 case MONO_PATCH_INFO_SWITCH:
151 ji->table_size = (int)data [0];
152 table = g_new (gpointer, ji->table_size);
153 ji->data.target = table;
154 for (i = 0; i < ji->table_size; i++) {
155 table [i] = data [i + 1];
158 case MONO_PATCH_INFO_R4:
159 case MONO_PATCH_INFO_R8:
160 ji->data.target = data;
163 g_warning ("unhandled type %d", ji->type);
164 g_assert_not_reached ();
168 ji->next = patch_info;
172 #ifndef PLATFORM_WIN32
173 /* disable write protection */
174 page_start = (char *) (((int) (code)) & ~ (PAGESIZE - 1));
175 pages = (code + code_len - page_start + PAGESIZE - 1) / PAGESIZE;
176 err = mprotect (page_start, pages * PAGESIZE, PROT_READ | PROT_WRITE | PROT_EXEC);
180 mono_arch_patch_code (method, mono_root_domain, code, patch_info);
181 mono_mempool_destroy (mp);
185 g_free (method_label);
189 info = mono_mempool_alloc0 (mono_root_domain->mp, sizeof (MonoJitInfo));
190 info->code_size = code_len;
191 info->used_regs = used_int_regs;
192 info->method = method;
193 info->code_start = code;
194 mono_jit_info_table_add (mono_root_domain, info);
196 mono_jit_stats.methods_aot++;
203 write_data_symbol (FILE *fp, const char *name, guint8 *buf, int size, int align)
207 fprintf (fp, ".globl %s\n", name);
208 fprintf (fp, ".data\n\t.align %d\n", align);
209 fprintf (fp, "\t.type %s,@object\n", name);
210 fprintf (fp, "\t.size %s,%d\n", name, size);
211 fprintf (fp, "%s:\n", name);
212 for (i = 0; i < size; i++) {
213 fprintf (fp, ".byte %d\n", buf [i]);
220 write_string_symbol (FILE *fp, const char *name, char *value)
222 fprintf (fp, ".globl %s\n", name);
223 fprintf (fp, ".data\n");
224 fprintf (fp, "%s:\n", name);
225 fprintf (fp, "\t.string \"%s\"\n", value);
229 mono_get_field_token (MonoClassField *field)
231 MonoClass *klass = field->parent;
234 for (i = 0; i < klass->field.count; ++i) {
235 if (field == &klass->fields [i])
236 return MONO_TOKEN_FIELD_DEF | (klass->field.first + 1 + i);
239 g_assert_not_reached ();
244 cond_emit_image_label (FILE *tmpfp, GHashTable *image_hash, MonoImage *image)
248 if ((label = g_hash_table_lookup (image_hash, image)))
251 label = g_strdup_printf ("image_patch_info_%p", image);
252 fprintf (tmpfp, "%s:\n", label);
253 fprintf (tmpfp, "\t.string \"%s\"\n", image->guid);
255 g_hash_table_insert (image_hash, image, label);
261 cond_emit_icall_label (FILE *tmpfp, GHashTable *hash, const char *icall_name)
265 if ((label = g_hash_table_lookup (hash, icall_name)))
268 label = g_strdup_printf ("icall_patch_info_%s", icall_name);
269 fprintf (tmpfp, "%s:\n", label);
270 fprintf (tmpfp, "\t.string \"%s\"\n", icall_name);
272 g_hash_table_insert (hash, (gpointer)icall_name, label);
278 cond_emit_method_label (FILE *tmpfp, GHashTable *hash, MonoJumpInfo *patch_info)
280 MonoMethod *method = patch_info->data.method;
283 if ((l1 = g_hash_table_lookup (hash, method)))
286 l2 = cond_emit_image_label (tmpfp, hash, method->klass->image);
287 fprintf (tmpfp, "\t.align %d\n", sizeof (gpointer));
288 l1 = g_strdup_printf ("method_patch_info_%08x_%p", method->token, method);
289 fprintf (tmpfp, "%s:\n", l1);
290 fprintf (tmpfp, "\t.long 0x%08x\n", method->token);
291 g_assert (method->token);
292 fprintf (tmpfp, "\t.long %s\n", l2);
294 g_hash_table_insert (hash, method, l1);
300 cond_emit_klass_label (FILE *tmpfp, GHashTable *hash, MonoClass *klass)
302 char *l1, *l2, *el = NULL;
304 if ((l1 = g_hash_table_lookup (hash, klass)))
307 if (!klass->type_token) {
308 g_assert (klass->rank > 0);
309 el = cond_emit_klass_label (tmpfp, hash, klass->element_class);
312 l2 = cond_emit_image_label (tmpfp, hash, klass->image);
313 fprintf (tmpfp, "\t.align %d\n", sizeof (gpointer));
314 l1 = g_strdup_printf ("klass_patch_info_%08x_%p", klass->type_token, klass);
315 fprintf (tmpfp, "%s:\n", l1);
316 fprintf (tmpfp, "\t.long 0x%08x\n", klass->type_token);
317 fprintf (tmpfp, "\t.long %s\n", l2);
320 fprintf (tmpfp, "\t.long %d\n", klass->rank);
321 fprintf (tmpfp, "\t.long %s\n", el);
324 g_hash_table_insert (hash, klass, l1);
330 cond_emit_field_label (FILE *tmpfp, GHashTable *hash, MonoJumpInfo *patch_info)
332 MonoClassField *field = patch_info->data.field;
336 if ((l1 = g_hash_table_lookup (hash, field)))
339 l2 = cond_emit_image_label (tmpfp, hash, field->parent->image);
340 fprintf (tmpfp, "\t.align %d\n", sizeof (gpointer));
341 token = mono_get_field_token (field);
342 l1 = g_strdup_printf ("klass_patch_info_%08x_%p", token, field);
343 fprintf (tmpfp, "%s:\n", l1);
344 fprintf (tmpfp, "\t.long 0x%08x\n", token);
346 fprintf (tmpfp, "\t.long %s\n", l2);
348 g_hash_table_insert (hash, field, l1);
354 mono_compile_assembly (MonoAssembly *ass, guint32 opts)
357 MonoImage *image = ass->image;
360 char *com, *tmpfname;
363 guint8 *code, *mname;
364 int ccount = 0, mcount = 0, lmfcount = 0, ecount = 0, abscount = 0, wrappercount = 0, ocount = 0;
365 GHashTable *ref_hash;
366 int func_alignment = 16;
368 printf ("Mono AOT compiler - compiling assembly %s\n", image->name);
370 tmpfname = g_strdup_printf ("%s/mono_aot_%05d", g_get_tmp_dir (), getpid ());
371 tmpfp = fopen (tmpfname, "w+");
374 ref_hash = g_hash_table_new (NULL, NULL);
376 write_string_symbol (tmpfp, "mono_assembly_guid" , image->guid);
378 for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
379 MonoJumpInfo *patch_info;
381 guint32 token = MONO_TOKEN_METHOD_DEF | (i + 1);
382 method = mono_get_method (image, token, NULL);
384 /* fixme: maybe we can also precompile wrapper methods */
385 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
386 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
387 (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
388 (method->flags & METHOD_ATTRIBUTE_ABSTRACT)) {
389 //printf ("Skip (impossible): %s\n", mono_method_full_name (method, TRUE));
395 /* fixme: we need to patch the IP for the LMF in that case */
396 if (method->save_lmf) {
397 //printf ("Skip (needs lmf): %s\n", mono_method_full_name (method, TRUE));
402 /* fixme: add methods with exception tables */
403 if (((MonoMethodNormal *)method)->header->num_clauses) {
404 //printf ("Skip (exceptions): %s\n", mono_method_full_name (method, TRUE));
409 //printf ("START: %s\n", mono_method_full_name (method, TRUE));
410 //mono_compile_method (method);
412 cfg = mini_method_compile (method, opts, mono_root_domain, 0);
415 if (cfg->disable_aot) {
421 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
422 if (patch_info->type == MONO_PATCH_INFO_ABS) {
423 /* unable to handle this */
424 //printf ("Skip (abs addr): %s %d\n", mono_method_full_name (method, TRUE), patch_info->type);
436 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
437 if ((patch_info->type == MONO_PATCH_INFO_METHOD ||
438 patch_info->type == MONO_PATCH_INFO_METHODCONST) &&
439 patch_info->data.method->wrapper_type) {
440 /* unable to handle this */
441 //printf ("Skip (wrapper call): %s %d\n", mono_method_full_name (method, TRUE), patch_info->type);
452 //printf ("Compile: %s\n", mono_method_full_name (method, TRUE));
454 code = cfg->native_code;
456 fprintf (tmpfp, ".text\n");
457 mname = g_strdup_printf ("method_%08X", token);
458 fprintf (tmpfp, "\t.align %d\n", func_alignment);
459 fprintf (tmpfp, ".globl %s\n", mname);
460 fprintf (tmpfp, "%s:\n", mname);
462 for (j = 0; j < cfg->code_len; j++)
463 fprintf (tmpfp, ".byte %d\n", (unsigned int) code [j]);
465 fprintf (tmpfp, ".data\n");
468 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
469 switch (patch_info->type) {
470 case MONO_PATCH_INFO_LABEL:
471 case MONO_PATCH_INFO_BB:
472 /* relative jumps are no problem, there is no need to handle then here */
474 case MONO_PATCH_INFO_SWITCH: {
475 gpointer *table = (gpointer *)patch_info->data.target;
478 fprintf (tmpfp, "\t.align %d\n", sizeof (gpointer));
479 fprintf (tmpfp, "%s_patch_info_%d:\n", mname, j);
480 fprintf (tmpfp, "\t.long %d\n", patch_info->table_size);
482 for (k = 0; k < patch_info->table_size; k++) {
483 fprintf (tmpfp, "\t.long %d\n", (guint8 *)table [k] - code);
488 case MONO_PATCH_INFO_INTERNAL_METHOD:
489 patch_info->data.name = cond_emit_icall_label (tmpfp, ref_hash, patch_info->data.name);
492 case MONO_PATCH_INFO_METHODCONST:
493 case MONO_PATCH_INFO_METHOD:
494 patch_info->data.name = cond_emit_method_label (tmpfp, ref_hash, patch_info);
497 case MONO_PATCH_INFO_FIELD:
498 patch_info->data.name = cond_emit_field_label (tmpfp, ref_hash, patch_info);
501 case MONO_PATCH_INFO_CLASS:
502 patch_info->data.name = cond_emit_klass_label (tmpfp, ref_hash, patch_info->data.klass);
505 case MONO_PATCH_INFO_IMAGE:
506 patch_info->data.name = cond_emit_image_label (tmpfp, ref_hash, patch_info->data.image);
509 case MONO_PATCH_INFO_R4:
510 fprintf (tmpfp, "\t.align 8\n");
511 fprintf (tmpfp, "%s_patch_info_%d:\n", mname, j);
512 fprintf (tmpfp, "\t.long 0x%08x\n", *((guint32 *)patch_info->data.target));
516 case MONO_PATCH_INFO_R8:
517 fprintf (tmpfp, "\t.align 8\n");
518 fprintf (tmpfp, "%s_patch_info_%d:\n", mname, j);
519 fprintf (tmpfp, "\t.long 0x%08x\n", *((guint32 *)patch_info->data.target));
520 fprintf (tmpfp, "\t.long 0x%08x\n", *((guint32 *)patch_info->data.target + 1));
525 g_warning ("unable to handle jump info %d", patch_info->type);
526 g_assert_not_reached ();
530 fprintf (tmpfp, ".globl %s_patch_info\n", mname);
531 fprintf (tmpfp, "\t.align %d\n", sizeof (gpointer));
532 fprintf (tmpfp, "%s_patch_info:\n", mname);
534 fprintf (tmpfp, "\t.long %d\n", cfg->code_len);
535 fprintf (tmpfp, "\t.long %d\n", cfg->used_int_regs);
537 fprintf (tmpfp, "\t.long %d\n", g_list_length (cfg->ldstr_list));
538 for (l = cfg->ldstr_list; l; l = l->next) {
539 fprintf (tmpfp, "\t.long 0x%08x\n", l->data);
544 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
545 switch (patch_info->type) {
546 case MONO_PATCH_INFO_METHODCONST:
547 case MONO_PATCH_INFO_METHOD:
548 case MONO_PATCH_INFO_CLASS:
549 case MONO_PATCH_INFO_FIELD:
550 case MONO_PATCH_INFO_INTERNAL_METHOD:
551 case MONO_PATCH_INFO_IMAGE:
552 fprintf (tmpfp, "\t.long %s\n", patch_info->data.name);
553 fprintf (tmpfp, "\t.long 0x%08x\n", ENCODE_TYPE_POS (patch_info->type, patch_info->ip.i));
556 case MONO_PATCH_INFO_SWITCH:
557 case MONO_PATCH_INFO_R4:
558 case MONO_PATCH_INFO_R8:
559 fprintf (tmpfp, "\t.long %s_patch_info_%d\n", mname, j);
560 fprintf (tmpfp, "\t.long 0x%08x\n", ENCODE_TYPE_POS (patch_info->type, patch_info->ip.i));
563 case MONO_PATCH_INFO_LABEL:
564 case MONO_PATCH_INFO_BB:
567 g_warning ("unable to handle jump info %d", patch_info->type);
568 g_assert_not_reached ();
573 /* NULL terminated array */
574 fprintf (tmpfp, "\t.long 0\n");
576 /* fixme: save the rest of the required infos */
579 mono_destroy_compile (cfg);
586 com = g_strdup_printf ("as %s -o %s.o;ld -shared -o %s.so %s.o;rm %s.o;strip --strip-unneeded --discard-all %s.so",
587 tmpfname, tmpfname, image->name, tmpfname, tmpfname, image->name);
589 printf ("Executing the native assembler now:\n%s\n", com);
592 printf ("Compile %d out of %d methods (%d%%)\n", ccount, mcount, (ccount*100)/mcount);
593 printf ("%d methods contains exception tables (%d%%)\n", ecount, (ecount*100)/mcount);
594 printf ("%d methods contains absolute addresses (%d%%)\n", abscount, (abscount*100)/mcount);
595 printf ("%d methods contains wrapper references (%d%%)\n", wrappercount, (wrappercount*100)/mcount);
596 printf ("%d methods contains lmf pointers (%d%%)\n", lmfcount, (lmfcount*100)/mcount);
597 printf ("%d methods has other problems (%d%%)\n", ocount, (ocount*100)/mcount);