2 * aot.c: mono Ahead of Time compiler
5 * Dietmar Maurer (dietmar@ximian.com)
7 * (C) 2002 Ximian, Inc.
11 #include <sys/types.h>
15 #ifndef PLATFORM_WIN32
23 #include <limits.h> /* for PAGESIZE */
28 #include <mono/metadata/tabledefs.h>
29 #include <mono/metadata/class.h>
30 #include <mono/metadata/object.h>
31 #include <mono/metadata/tokentype.h>
32 #include <mono/metadata/appdomain.h>
33 #include <mono/metadata/debug-helpers.h>
34 #include <mono/metadata/assembly.h>
35 #include <mono/metadata/metadata-internals.h>
36 #include <mono/metadata/marshal.h>
37 #include <mono/utils/mono-logger.h>
38 #include <mono/os/gc_wrapper.h>
43 #define SHARED_EXT ".dll"
44 #elif defined(__ppc__) && defined(__MACH__)
45 #define SHARED_EXT ".dylib"
47 #define SHARED_EXT ".so"
50 #if defined(sparc) || defined(__ppc__)
51 #define AS_STRING_DIRECTIVE ".asciz"
54 #define AS_STRING_DIRECTIVE ".string"
57 #define ALIGN_PTR_TO(ptr,align) (gpointer)((((gssize)(ptr)) + (align - 1)) & (~(align - 1)))
59 typedef struct MonoAotMethod {
61 MonoJumpInfo *patch_info;
65 typedef struct MonoAotModule {
66 /* Optimization flags used to compile the module */
68 /* Maps MonoMethods to MonoAotMethodInfos */
69 MonoGHashTable *methods;
71 MonoImage **image_table;
72 guint32* methods_present_table;
75 typedef struct MonoAotCompile {
78 GHashTable *icall_hash;
79 GPtrArray *icall_table;
80 GHashTable *image_hash;
81 GPtrArray *image_table;
84 typedef struct MonoAotOptions {
88 static MonoGHashTable *aot_modules;
90 static CRITICAL_SECTION aot_mutex;
93 * Disabling this will make a copy of the loaded code and use the copy instead
94 * of the original. This will place the caller and the callee close to each
95 * other in memory, possibly improving cache behavior. Since the original
96 * code is in copy-on-write memory, this will not increase the memory usage
99 static gboolean use_loaded_code = FALSE;
102 * Whenever to AOT compile loaded assemblies on demand and store them in
103 * a cache under $HOME/.mono/aot-cache.
105 static gboolean use_aot_cache = FALSE;
108 static gint32 mono_last_aot_method = -1;
111 mono_aot_load_method (MonoDomain *domain, MonoAotModule *aot_module, MonoMethod *method, guint8 *code, guint8 *info);
114 decode_class_info (MonoAotModule *module, guint32 *data)
119 image = module->image_table [data [1]];
123 return mono_class_get (image, data [0]);
125 /* the pointer is dword aligned */
126 klass = decode_class_info (module, *(guint32**)(ALIGN_PTR_TO (&data[3], sizeof (gpointer))));
127 return mono_array_class_get (klass, data [2]);
134 create_cache_structure (void)
140 home = g_get_home_dir ();
144 tmp = g_build_filename (home, ".mono", NULL);
145 if (!g_file_test (tmp, G_FILE_TEST_IS_DIR)) {
146 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT creating directory %s", tmp);
147 #ifdef PLATFORM_WIN32
150 err = mkdir (tmp, 0777);
153 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT failed: %s", g_strerror (errno));
159 tmp = g_build_filename (home, ".mono", "aot-cache", NULL);
160 if (!g_file_test (tmp, G_FILE_TEST_IS_DIR)) {
161 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT creating directory %s", tmp);
162 #ifdef PLATFORM_WIN32
165 err = mkdir (tmp, 0777);
168 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT failed: %s", g_strerror (errno));
177 * load_aot_module_from_cache:
179 * Experimental code to AOT compile loaded assemblies on demand.
182 * - Add environment variable MONO_AOT_CACHE_OPTIONS
183 * - Add options for controlling the cache size
184 * - Handle full cache by deleting old assemblies lru style
185 * - Add options for excluding assemblies during development
186 * - Maybe add a threshold after an assembly is AOT compiled
187 * - invoking a new mono process is a security risk
190 load_aot_module_from_cache (MonoAssembly *assembly, char **aot_name)
192 char *fname, *cmd, *tmp2;
200 if (assembly->image->dynamic)
203 create_cache_structure ();
205 home = g_get_home_dir ();
207 tmp2 = g_strdup_printf ("%s-%s%s", assembly->image->assembly_name, assembly->image->guid, SHARED_EXT);
208 fname = g_build_filename (home, ".mono", "aot-cache", tmp2, NULL);
212 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT trying to load from cache: '%s'.", fname);
213 module = g_module_open (fname, G_MODULE_BIND_LAZY);
216 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT not found.");
218 mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT precompiling assembly '%s'... ", assembly->image->name);
220 /* FIXME: security */
221 cmd = g_strdup_printf ("mono -O=all --aot=outfile=%s %s", fname, assembly->image->name);
223 res = g_spawn_command_line_sync (cmd, &out, &err, NULL, NULL);
226 mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT failed.");
230 mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT succeeded.");
232 module = g_module_open (fname, G_MODULE_BIND_LAZY);
239 load_aot_module (MonoAssembly *assembly, gpointer user_data)
243 gboolean usable = TRUE;
244 char *saved_guid = NULL;
245 char *aot_version = NULL;
246 char *opt_flags = NULL;
248 if (mono_compile_aot)
252 assembly->aot_module = load_aot_module_from_cache (assembly, &aot_name);
254 aot_name = g_strdup_printf ("%s%s", assembly->image->name, SHARED_EXT);
256 assembly->aot_module = g_module_open (aot_name, G_MODULE_BIND_LAZY);
258 if (!assembly->aot_module) {
259 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT failed to load AOT module %s: %s\n", aot_name, g_module_error ());
263 if (!assembly->aot_module) {
268 g_module_symbol (assembly->aot_module, "mono_assembly_guid", (gpointer *) &saved_guid);
269 g_module_symbol (assembly->aot_module, "mono_aot_version", (gpointer *) &aot_version);
270 g_module_symbol (assembly->aot_module, "mono_aot_opt_flags", (gpointer *)&opt_flags);
272 if (!aot_version || strcmp (aot_version, MONO_AOT_FILE_VERSION)) {
273 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT module %s has wrong file format version (expected %s got %s)\n", aot_name, MONO_AOT_FILE_VERSION, aot_version);
277 if (!saved_guid || strcmp (assembly->image->guid, saved_guid)) {
278 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT module %s is out of date.\n", aot_name);
284 g_module_close (assembly->aot_module);
285 assembly->aot_module = NULL;
290 * It seems that MonoGHashTables are in the GC heap, so structures
291 * containing them must be in the GC heap as well :(
294 info = GC_MALLOC (sizeof (MonoAotModule));
296 info = g_new0 (MonoAotModule, 1);
298 info->methods = mono_g_hash_table_new (NULL, NULL);
299 sscanf (opt_flags, "%d", &info->opts);
301 /* Read image table */
303 guint32 table_len, i;
306 g_module_symbol (assembly->aot_module, "mono_image_table", (gpointer *)&table);
309 table_len = *(guint32*)table;
310 table += sizeof (guint32);
311 info->image_table = g_new0 (MonoImage*, table_len);
312 for (i = 0; i < table_len; ++i) {
313 info->image_table [i] = mono_image_loaded_by_guid (table);
314 if (!info->image_table [i]) {
315 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT module %s is out of date.\n", aot_name);
316 mono_g_hash_table_destroy (info->methods);
317 g_free (info->image_table);
318 #ifndef HAVE_BOEHM_GC
322 g_module_close (assembly->aot_module);
323 assembly->aot_module = NULL;
326 table += strlen (table) + 1;
330 /* Read icall table */
332 guint32 table_len, i;
335 g_module_symbol (assembly->aot_module, "mono_icall_table", (gpointer *)&table);
338 table_len = *(guint32*)table;
339 table += sizeof (guint32);
340 info->icall_table = g_new0 (char*, table_len);
341 for (i = 0; i < table_len; ++i) {
342 info->icall_table [i] = table;
343 table += strlen (table) + 1;
347 /* Read methods present table */
348 g_module_symbol (assembly->aot_module, "mono_methods_present_table", (gpointer *)&info->methods_present_table);
349 g_assert (info->methods_present_table);
351 EnterCriticalSection (&aot_mutex);
352 mono_g_hash_table_insert (aot_modules, assembly, info);
353 LeaveCriticalSection (&aot_mutex);
355 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT loaded AOT Module for %s.\n", assembly->image->name);
361 InitializeCriticalSection (&aot_mutex);
363 MONO_GC_REGISTER_ROOT (aot_modules);
364 aot_modules = mono_g_hash_table_new (NULL, NULL);
366 mono_install_assembly_load_hook (load_aot_module, NULL);
368 if (getenv ("MONO_LASTAOT"))
369 mono_last_aot_method = atoi (getenv ("MONO_LASTAOT"));
373 mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method)
375 MonoClass *klass = method->klass;
376 MonoAssembly *ass = klass->image->assembly;
377 GModule *module = ass->aot_module;
378 char method_label [256];
379 char info_label [256];
382 MonoAotModule *aot_module;
383 MonoAotMethod *minfo;
385 MonoMethodHeader *header = ((MonoMethodNormal*)method)->header;
394 if (mono_profiler_get_events () & MONO_PROFILE_ENTER_LEAVE)
397 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
398 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
399 (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
400 (method->flags & METHOD_ATTRIBUTE_ABSTRACT))
403 aot_module = (MonoAotModule*)mono_g_hash_table_lookup (aot_modules, ass);
405 g_assert (klass->inited);
407 minfo = mono_g_hash_table_lookup (aot_module->methods, method);
408 /* Can't use code from non-root domains since they can be unloaded */
409 if (minfo && (minfo->domain == mono_get_root_domain ())) {
410 /* This method was already loaded in another appdomain */
412 /* Duplicate jinfo */
413 jinfo = mono_mempool_alloc0 (domain->mp, sizeof (MonoJitInfo));
414 memcpy (jinfo, minfo->info, sizeof (MonoJitInfo));
415 if (jinfo->clauses) {
417 mono_mempool_alloc0 (domain->mp, sizeof (MonoJitExceptionInfo) * header->num_clauses);
418 memcpy (jinfo->clauses, minfo->info->clauses, sizeof (MonoJitExceptionInfo) * header->num_clauses);
421 if (aot_module->opts & MONO_OPT_SHARED)
422 /* Use the same method in the new appdomain */
424 else if (!minfo->patch_info)
425 /* Use the same method in the new appdomain */
428 /* Create a copy of the original method and apply relocations */
430 code = mono_code_manager_reserve (domain->code_mp, minfo->info->code_size);
431 memcpy (code, minfo->info->code_start, minfo->info->code_size);
433 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT REUSE METHOD: %s %p - %p.\n", mono_method_full_name (method, TRUE), code, (char*)code + minfo->info->code_size);
435 /* Do this outside the lock to avoid deadlocks */
436 LeaveCriticalSection (&aot_mutex);
437 mono_arch_patch_code (method, domain, code, minfo->patch_info, TRUE);
438 EnterCriticalSection (&aot_mutex);
439 mono_arch_flush_icache (code, minfo->info->code_size);
442 jinfo->code_start = code;
443 if (jinfo->clauses) {
444 for (i = 0; i < header->num_clauses; ++i) {
445 MonoJitExceptionInfo *ei = &jinfo->clauses [i];
446 gint32 offset = code - (guint8*)minfo->info->code_start;
448 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)
449 ei->data.filter = (guint8*)ei->data.filter + offset;
450 ei->try_start = (guint8*)ei->try_start + offset;
451 ei->try_end = (guint8*)ei->try_end + offset;
452 ei->handler_start = (guint8*)ei->handler_start + offset;
460 /* Do a fast check to see whenever the method exists */
462 guint32 index = mono_metadata_token_index (method->token) - 1;
464 w = aot_module->methods_present_table [index / 32];
465 if (! (w & (1 << (index % 32)))) {
466 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT NOT FOUND: %s.\n", mono_method_full_name (method, TRUE));
471 sprintf (method_label, "m_%x", mono_metadata_token_index (method->token));
473 if (!g_module_symbol (module, method_label, (gpointer *)&code))
476 sprintf (info_label, "%s_p", method_label);
478 if (!g_module_symbol (module, info_label, (gpointer *)&info))
481 if (mono_last_aot_method != -1) {
482 if (mono_jit_stats.methods_aot > mono_last_aot_method)
485 if (mono_jit_stats.methods_aot == mono_last_aot_method)
486 printf ("LAST AOT METHOD: %s.%s.%s.\n", klass->name_space, klass->name, method->name);
489 return mono_aot_load_method (domain, aot_module, method, code, info);
493 mono_aot_load_method (MonoDomain *domain, MonoAotModule *aot_module, MonoMethod *method, guint8 *code, guint8 *info)
495 MonoClass *klass = method->klass;
496 MonoJumpInfo *patch_info = NULL;
497 guint code_len, used_int_regs, used_strings;
498 MonoAotMethod *minfo;
500 MonoMethodHeader *header = ((MonoMethodNormal*)method)->header;
505 minfo = GC_MALLOC (sizeof (MonoAotMethod));
507 minfo = g_new0 (MonoAotMethod, 1);
510 minfo->domain = domain;
511 jinfo = mono_mempool_alloc0 (domain->mp, sizeof (MonoJitInfo));
513 code_len = *(guint32*)info;
515 used_int_regs = *(guint32*)info;
518 if (!use_loaded_code) {
520 code2 = mono_code_manager_reserve (domain->code_mp, code_len);
521 memcpy (code2, code, code_len);
522 mono_arch_flush_icache (code2, code_len);
526 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT FOUND AOT compiled code for %s %p - %p %p\n", mono_method_full_name (method, TRUE), code, code + code_len, info);
528 /* Exception table */
529 if (header->num_clauses) {
531 mono_mempool_alloc0 (domain->mp, sizeof (MonoJitExceptionInfo) * header->num_clauses);
532 jinfo->num_clauses = header->num_clauses;
534 jinfo->exvar_offset = *(guint32*)info;
537 for (i = 0; i < header->num_clauses; ++i) {
538 MonoExceptionClause *ec = &header->clauses [i];
539 MonoJitExceptionInfo *ei = &jinfo->clauses [i];
541 ei->flags = ec->flags;
542 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)
543 ei->data.filter = code + *(guint32*)info;
545 ei->data.token = *(guint32*)info;
547 ei->try_start = code + *(guint32*)info;
549 ei->try_end = code + *(guint32*)info;
551 ei->handler_start = code + *(guint32*)info;
556 if (aot_module->opts & MONO_OPT_SHARED) {
557 used_strings = *(guint32*)info;
563 for (i = 0; i < used_strings; i++) {
564 guint token = *(guint32*)info;
566 mono_ldstr (mono_get_root_domain (), klass->image, mono_metadata_token_index (token));
576 guint32 last_offset, buf_len;
579 if (aot_module->opts & MONO_OPT_SHARED)
580 mp = mono_mempool_new ();
584 /* First load the type + offset table */
586 patches = g_ptr_array_new ();
588 MonoJumpInfo *ji = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
593 b2 = *((guint8*)info + 1);
599 if (((b1 & (1 + 2)) == 3) && (b2 == 255)) {
600 info = ALIGN_PTR_TO (info, 4);
601 ji->ip.i = *(guint32*)info;
605 ji->ip.i = (((guint32)(b1 & (1 + 2))) << 8) + b2;
607 ji->ip.i += last_offset;
608 last_offset = ji->ip.i;
609 //printf ("T: %d O: %d.\n", ji->type, ji->ip.i);
611 ji->next = patch_info;
614 g_ptr_array_add (patches, ji);
618 info = ALIGN_PTR_TO (info, sizeof (gpointer));
620 /* Then load the other data */
621 for (pindex = 0; pindex < patches->len; ++pindex) {
622 MonoJumpInfo *ji = g_ptr_array_index (patches, pindex);
624 data = *((guint32 **)info);
625 info += sizeof (gpointer);
628 case MONO_PATCH_INFO_CLASS:
629 case MONO_PATCH_INFO_IID:
630 ji->data.klass = decode_class_info (aot_module, data);
631 g_assert (ji->data.klass);
632 mono_class_init (ji->data.klass);
634 case MONO_PATCH_INFO_VTABLE:
635 case MONO_PATCH_INFO_CLASS_INIT:
636 ji->data.klass = decode_class_info (aot_module, data);
637 g_assert (ji->data.klass);
638 mono_class_init (ji->data.klass);
640 case MONO_PATCH_INFO_IMAGE:
641 ji->data.image = aot_module->image_table [(guint32)data];
642 g_assert (ji->data.image);
644 case MONO_PATCH_INFO_METHOD:
645 case MONO_PATCH_INFO_METHODCONST:
646 case MONO_PATCH_INFO_METHOD_JUMP: {
647 guint32 image_index, token;
649 image_index = (guint32)data >> 24;
650 token = MONO_TOKEN_METHOD_DEF | ((guint32)data & 0xffffff);
652 image = aot_module->image_table [image_index];
653 ji->data.method = mono_get_method (image, token, NULL);
654 g_assert (ji->data.method);
655 mono_class_init (ji->data.method->klass);
659 case MONO_PATCH_INFO_WRAPPER: {
660 guint32 wrapper_type;
662 wrapper_type = (guint32)data[0];
664 switch (wrapper_type) {
665 case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK: {
666 guint32 image_index, token;
668 image_index = (guint32)data[1] >> 24;
669 token = MONO_TOKEN_METHOD_DEF | ((guint32)data[1] & 0xffffff);
671 image = aot_module->image_table [image_index];
672 ji->data.method = mono_get_method (image, token, NULL);
673 g_assert (ji->data.method);
674 mono_class_init (ji->data.method->klass);
676 ji->type = MONO_PATCH_INFO_METHOD;
677 ji->data.method = mono_marshal_get_remoting_invoke_with_check (ji->data.method);
680 case MONO_WRAPPER_PROXY_ISINST: {
681 /* The pointer is dword aligned */
682 gpointer class_ptr = *(gpointer*)(ALIGN_PTR_TO (&data[1], sizeof (gpointer)));
683 MonoClass *klass = decode_class_info (aot_module, class_ptr);
684 mono_class_init (klass);
685 ji->type = MONO_PATCH_INFO_METHODCONST;
686 ji->data.method = mono_marshal_get_proxy_cancast (klass);
689 case MONO_WRAPPER_LDFLD:
690 case MONO_WRAPPER_STFLD: {
691 /* The pointer is dword aligned */
692 gpointer class_ptr = *(gpointer*)(ALIGN_PTR_TO (&data[1], sizeof (gpointer)));
693 MonoClass *klass = decode_class_info (aot_module, class_ptr);
694 mono_class_init (klass);
695 ji->type = MONO_PATCH_INFO_METHOD;
696 if (wrapper_type == MONO_WRAPPER_LDFLD)
697 ji->data.method = mono_marshal_get_ldfld_wrapper (&klass->byval_arg);
699 ji->data.method = mono_marshal_get_stfld_wrapper (&klass->byval_arg);
703 g_assert_not_reached ();
707 case MONO_PATCH_INFO_FIELD:
708 case MONO_PATCH_INFO_SFLDA: {
709 /* The pointer is dword aligned */
710 gpointer class_ptr = *(gpointer*)(ALIGN_PTR_TO (&data[1], sizeof (gpointer)));
711 MonoClass *klass = decode_class_info (aot_module, class_ptr);
712 mono_class_init (klass);
713 ji->data.field = mono_class_get_field (klass, data [0]);
716 case MONO_PATCH_INFO_INTERNAL_METHOD:
717 ji->data.name = aot_module->icall_table [(guint32)data];
718 g_assert (ji->data.name);
719 //printf ("A: %s.\n", ji->data.name);
721 case MONO_PATCH_INFO_SWITCH:
722 ji->table_size = data [0];
723 table = g_new (gpointer, ji->table_size);
724 ji->data.target = table;
725 for (i = 0; i < ji->table_size; i++) {
726 table [i] = (gpointer)data [i + 1];
729 case MONO_PATCH_INFO_R4:
730 case MONO_PATCH_INFO_R8:
731 ji->data.target = data;
733 case MONO_PATCH_INFO_LDSTR:
734 case MONO_PATCH_INFO_LDTOKEN:
735 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
736 image = aot_module->image_table [data [0]];
737 ji->data.token = mono_jump_info_token_new (mp, image, data [1]);
739 case MONO_PATCH_INFO_EXC_NAME:
740 ji->data.klass = decode_class_info (aot_module, data);
741 g_assert (ji->data.klass);
742 mono_class_init (ji->data.klass);
743 ji->data.name = ji->data.klass->name;
745 case MONO_PATCH_INFO_METHOD_REL:
746 ji->data.offset = data [0];
749 g_warning ("unhandled type %d", ji->type);
750 g_assert_not_reached ();
754 g_ptr_array_free (patches, TRUE);
756 buf_len = *(guint32*)info;
758 mono_debug_add_aot_method (domain, method, code, info, buf_len);
760 if (use_loaded_code) {
761 /* disable write protection */
762 #ifndef PLATFORM_WIN32
763 page_start = (char *) (((int) (code)) & ~ (PAGESIZE - 1));
764 pages = (code + code_len - page_start + PAGESIZE - 1) / PAGESIZE;
765 err = mprotect (page_start, pages * PAGESIZE, PROT_READ | PROT_WRITE | PROT_EXEC);
770 g_assert (VirtualProtect (code, code_len, PAGE_EXECUTE_READWRITE, &oldp) != 0);
775 /* Do this outside the lock to avoid deadlocks */
776 LeaveCriticalSection (&aot_mutex);
777 mono_arch_patch_code (method, domain, code, patch_info, TRUE);
778 EnterCriticalSection (&aot_mutex);
780 if (aot_module->opts & MONO_OPT_SHARED)
781 /* No need to cache patches */
782 mono_mempool_destroy (mp);
784 minfo->patch_info = patch_info;
787 mono_jit_stats.methods_aot++;
790 jinfo->code_size = code_len;
791 jinfo->used_regs = used_int_regs;
792 jinfo->method = method;
793 jinfo->code_start = code;
794 jinfo->domain_neutral = (aot_module->opts & MONO_OPT_SHARED) != 0;
797 mono_g_hash_table_insert (aot_module->methods, method, minfo);
804 mono_aot_get_method (MonoDomain *domain, MonoMethod *method)
808 EnterCriticalSection (&aot_mutex);
809 info = mono_aot_get_method_inner (domain, method);
810 LeaveCriticalSection (&aot_mutex);
812 /* Do this outside the lock */
814 mono_jit_info_table_add (domain, info);
822 emit_section_change (FILE *fp, const char *section_name, int subsection_index)
825 /* For solaris as, GNU as should accept the same */
826 fprintf (fp, ".section \"%s\"\n", section_name);
827 #elif defined(__ppc__) && defined(__MACH__)
828 /* This needs to be made more precise on mach. */
829 fprintf (fp, "%s\n", subsection_index == 0 ? ".text" : ".data");
831 fprintf (fp, "%s %d\n", section_name, subsection_index);
836 emit_global (FILE *fp, const char *name)
838 #if defined(__ppc__) && defined(__MACH__)
839 // mach-o always uses a '_' prefix.
840 fprintf (fp, ".globl _%s\n", name);
842 fprintf (fp, ".globl %s\n", name);
847 emit_label (FILE *fp, const char *name)
849 #if defined(__ppc__) && defined(__MACH__)
850 // mach-o always uses a '_' prefix.
851 fprintf (fp, "_%s:\n", name);
853 fprintf (fp, "%s:\n", name);
859 write_data_symbol (FILE *fp, const char *name, guint8 *buf, int size, int align)
863 emit_section_change (fp, ".text", 1);
865 fprintf (fp, ".globl %s\n", name);
866 fprintf (fp, "\t.align %d\n", align);
867 fprintf (fp, "\t.type %s,#object\n", name);
868 fprintf (fp, "\t.size %s,%d\n", name, size);
869 fprintf (fp, "%s:\n", name);
870 for (i = 0; i < size; i++) {
871 fprintf (fp, ".byte %d\n", buf [i]);
878 write_string_symbol (FILE *fp, const char *name, const char *value)
880 emit_section_change (fp, ".text", 1);
881 emit_global(fp, name);
882 emit_label(fp, name);
883 fprintf (fp, "\t%s \"%s\"\n", AS_STRING_DIRECTIVE, value);
887 mono_get_field_token (MonoClassField *field)
889 MonoClass *klass = field->parent;
892 for (i = 0; i < klass->field.count; ++i) {
893 if (field == &klass->fields [i])
894 return MONO_TOKEN_FIELD_DEF | (klass->field.first + 1 + i);
897 g_assert_not_reached ();
902 get_image_index (MonoAotCompile *cfg, MonoImage *image)
906 index = GPOINTER_TO_UINT (g_hash_table_lookup (cfg->image_hash, image));
910 index = g_hash_table_size (cfg->image_hash);
911 g_hash_table_insert (cfg->image_hash, image, GUINT_TO_POINTER (index + 1));
912 g_ptr_array_add (cfg->image_table, image);
918 emit_image_index (MonoAotCompile *cfg, MonoImage *image)
922 image_index = get_image_index (cfg, image);
924 fprintf (cfg->fp, "\t.long %d\n", image_index);
927 #if defined(__ppc__) && defined(__MACH__)
929 ilog2(register int value)
932 while (value & ~0xf) count += 4, value >>= 4;
933 while (value) count++, value >>= 1;
938 static void emit_alignment(FILE *fp, int size)
940 #if defined(__ppc__) && defined(__MACH__)
941 // the mach-o assembler specifies alignments as powers of 2.
942 fprintf (fp, "\t.align %d\t; ilog2\n", ilog2(size));
943 #elif defined(__powerpc__)
944 /* ignore on linux/ppc */
946 fprintf (fp, "\t.align %d\n", size);
951 emit_pointer (FILE *fp, const char *target)
953 emit_alignment (fp, sizeof (gpointer));
954 #if defined(sparc) && SIZEOF_VOID_P == 8
955 fprintf (fp, "\t.xword %s\n", target);
957 fprintf (fp, "\t.long %s\n", target);
962 cond_emit_klass_label (MonoAotCompile *cfg, MonoClass *klass)
964 char *l1, *el = NULL;
966 if ((l1 = g_hash_table_lookup (cfg->ref_hash, klass)))
969 if (!klass->type_token) {
970 g_assert (klass->rank > 0);
971 el = cond_emit_klass_label (cfg, klass->element_class);
974 emit_alignment(cfg->fp, sizeof (gpointer));
976 l1 = g_strdup_printf ("klass_p_%08x_%p", klass->type_token, klass);
977 fprintf (cfg->fp, "%s:\n", l1);
978 fprintf (cfg->fp, "\t.long 0x%08x\n", klass->type_token);
979 emit_image_index (cfg, klass->image);
982 fprintf (cfg->fp, "\t.long %d\n", klass->rank);
983 emit_pointer (cfg->fp, el);
986 g_hash_table_insert (cfg->ref_hash, klass, l1);
992 cond_emit_field_label (MonoAotCompile *cfg, MonoJumpInfo *patch_info)
994 MonoClassField *field = patch_info->data.field;
998 if ((l1 = g_hash_table_lookup (cfg->ref_hash, field)))
1001 l2 = cond_emit_klass_label (cfg, field->parent);
1002 emit_alignment(cfg->fp, sizeof (gpointer));
1003 token = mono_get_field_token (field);
1005 l1 = g_strdup_printf ("klass_p_%08x_%p", token, field);
1006 fprintf (cfg->fp, "%s:\n", l1);
1007 fprintf (cfg->fp, "\t.long 0x%08x\n", token);
1008 emit_pointer (cfg->fp, l2);
1010 g_hash_table_insert (cfg->ref_hash, field, l1);
1016 compare_patches (gconstpointer a, gconstpointer b)
1020 i = (*(MonoJumpInfo**)a)->ip.i;
1021 j = (*(MonoJumpInfo**)b)->ip.i;
1033 emit_method (MonoAotCompile *acfg, MonoCompile *cfg)
1038 int i, j, k, pindex;
1039 guint8 *code, *mname, *mname_p;
1040 int func_alignment = 16;
1042 MonoJumpInfo *patch_info;
1043 MonoMethodHeader *header;
1046 method = cfg->method;
1047 code = cfg->native_code;
1048 header = ((MonoMethodNormal*)method)->header;
1050 emit_section_change (tmpfp, ".text", 0);
1051 mname = g_strdup_printf ("m_%x", mono_metadata_token_index (method->token));
1052 mname_p = g_strdup_printf ("%s_p", mname);
1053 emit_alignment(tmpfp, func_alignment);
1054 emit_global(tmpfp, mname);
1056 fprintf (tmpfp, "\t.type %s,#function\n", mname);
1057 #elif !(defined(__ppc__) && defined(__MACH__))
1058 fprintf (tmpfp, "\t.type %s,@function\n", mname);
1060 emit_label(tmpfp, mname);
1062 for (i = 0; i < cfg->code_len; i++)
1063 fprintf (tmpfp, ".byte %d\n", (unsigned int) code [i]);
1065 emit_section_change (tmpfp, ".text", 1);
1067 /* Sort relocations */
1068 patches = g_ptr_array_new ();
1069 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next)
1070 g_ptr_array_add (patches, patch_info);
1071 g_ptr_array_sort (patches, compare_patches);
1073 /* Emit out of line info for relocations */
1075 for (pindex = 0; pindex < patches->len; ++pindex) {
1076 patch_info = g_ptr_array_index (patches, pindex);
1077 switch (patch_info->type) {
1078 case MONO_PATCH_INFO_LABEL:
1079 case MONO_PATCH_INFO_BB:
1080 /* relative jumps are no problem, there is no need to handle then here */
1082 case MONO_PATCH_INFO_SWITCH: {
1083 gpointer *table = (gpointer *)patch_info->data.target;
1086 emit_alignment(tmpfp, sizeof (gpointer));
1087 fprintf (tmpfp, "%s_p_%d:\n", mname, j);
1088 fprintf (tmpfp, "\t.long %d\n", patch_info->table_size);
1090 for (k = 0; k < patch_info->table_size; k++) {
1091 fprintf (tmpfp, "\t.long %d\n", (int)table [k]);
1096 case MONO_PATCH_INFO_INTERNAL_METHOD: {
1097 guint32 icall_index;
1099 icall_index = (guint32)g_hash_table_lookup (acfg->icall_hash, patch_info->data.name);
1101 icall_index = g_hash_table_size (acfg->icall_hash) + 1;
1102 g_hash_table_insert (acfg->icall_hash, (gpointer)patch_info->data.name,
1103 GUINT_TO_POINTER (icall_index));
1104 g_ptr_array_add (acfg->icall_table, (gpointer)patch_info->data.name);
1106 patch_info->data.name = g_strdup_printf ("%d", icall_index - 1);
1110 case MONO_PATCH_INFO_METHODCONST:
1111 case MONO_PATCH_INFO_METHOD:
1112 case MONO_PATCH_INFO_METHOD_JUMP: {
1114 * The majority of patches are for methods, so we emit
1115 * them inline instead of defining a label for them to
1116 * decrease the number of relocations.
1118 guint32 image_index = get_image_index (acfg, patch_info->data.method->klass->image);
1119 guint32 token = patch_info->data.method->token;
1120 g_assert (image_index < 256);
1121 g_assert (mono_metadata_token_table (token) == MONO_TABLE_METHOD);
1123 patch_info->data.name =
1124 g_strdup_printf ("%d", (image_index << 24) + (mono_metadata_token_index (token)));
1128 case MONO_PATCH_INFO_WRAPPER: {
1129 switch (patch_info->data.method->wrapper_type) {
1130 case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK: {
1132 guint32 image_index;
1135 m = mono_marshal_method_from_wrapper (patch_info->data.method);
1136 image_index = get_image_index (acfg, m->klass->image);
1138 g_assert (image_index < 256);
1139 g_assert (mono_metadata_token_table (token) == MONO_TABLE_METHOD);
1140 emit_alignment(tmpfp, sizeof (gpointer));
1141 fprintf (tmpfp, "%s_p_%d:\n", mname, j);
1142 fprintf (tmpfp, "\t.long %d\n", patch_info->data.method->wrapper_type);
1143 fprintf (tmpfp, "\t.long %d\n", (image_index << 24) + (mono_metadata_token_index (token)));
1146 case MONO_WRAPPER_PROXY_ISINST:
1147 case MONO_WRAPPER_LDFLD:
1148 case MONO_WRAPPER_STFLD: {
1149 MonoClass *proxy_class = (MonoClass*)mono_marshal_method_from_wrapper (patch_info->data.method);
1150 char *klass_label = cond_emit_klass_label (acfg, proxy_class);
1152 fprintf (tmpfp, "%s_p_%d:\n", mname, j);
1153 fprintf (tmpfp, "\t.long %d\n", patch_info->data.method->wrapper_type);
1154 emit_pointer (tmpfp, klass_label);
1158 g_assert_not_reached ();
1163 case MONO_PATCH_INFO_FIELD:
1164 patch_info->data.name = cond_emit_field_label (acfg, patch_info);
1167 case MONO_PATCH_INFO_CLASS:
1168 case MONO_PATCH_INFO_IID:
1169 patch_info->data.name = cond_emit_klass_label (acfg, patch_info->data.klass);
1172 case MONO_PATCH_INFO_IMAGE:
1173 patch_info->data.name = g_strdup_printf ("%d", get_image_index (acfg, patch_info->data.image));
1176 case MONO_PATCH_INFO_EXC_NAME: {
1177 MonoClass *ex_class;
1180 mono_class_from_name (mono_defaults.exception_class->image,
1181 "System", patch_info->data.target);
1182 g_assert (ex_class);
1183 patch_info->data.name = cond_emit_klass_label (acfg, ex_class);
1187 case MONO_PATCH_INFO_R4:
1188 emit_alignment(tmpfp, 8);
1189 fprintf (tmpfp, "%s_p_%d:\n", mname, j);
1190 fprintf (tmpfp, "\t.long 0x%08x\n", *((guint32 *)patch_info->data.target));
1193 case MONO_PATCH_INFO_R8:
1194 emit_alignment(tmpfp, 8);
1195 fprintf (tmpfp, "%s_p_%d:\n", mname, j);
1196 fprintf (tmpfp, "\t.long 0x%08x\n", *((guint32 *)patch_info->data.target));
1197 fprintf (tmpfp, "\t.long 0x%08x\n", *((guint32 *)patch_info->data.target + 1));
1200 case MONO_PATCH_INFO_METHOD_REL:
1201 emit_alignment(tmpfp, sizeof (gpointer));
1202 fprintf (tmpfp, "%s_p_%d:\n", mname, j);
1203 fprintf (tmpfp, "\t.long 0x%08x\n", patch_info->data.offset);
1206 case MONO_PATCH_INFO_VTABLE:
1207 case MONO_PATCH_INFO_CLASS_INIT:
1208 patch_info->data.name = cond_emit_klass_label (acfg, patch_info->data.klass);
1211 case MONO_PATCH_INFO_SFLDA:
1212 patch_info->data.name = cond_emit_field_label (acfg, patch_info);
1215 case MONO_PATCH_INFO_LDSTR:
1216 case MONO_PATCH_INFO_LDTOKEN:
1217 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1218 emit_alignment(tmpfp, 8);
1219 fprintf (tmpfp, "%s_p_%d:\n", mname, j);
1220 fprintf (tmpfp, "\t.long 0x%08x\n", get_image_index (acfg, patch_info->data.token->image));
1221 fprintf (tmpfp, "\t.long 0x%08x\n", patch_info->data.token->token);
1225 g_warning ("unable to handle jump info %d", patch_info->type);
1226 g_assert_not_reached ();
1230 emit_global (tmpfp, mname_p);
1231 emit_alignment (tmpfp, sizeof (gpointer));
1232 emit_label (tmpfp, mname_p);
1234 fprintf (tmpfp, "\t.long %d\n", cfg->code_len);
1235 fprintf (tmpfp, "\t.long %ld\n", (long)cfg->used_int_regs);
1237 /* Exception table */
1238 if (header->num_clauses) {
1239 MonoJitInfo *jinfo = cfg->jit_info;
1241 fprintf (tmpfp, "\t.long %d\n", jinfo->exvar_offset);
1243 for (k = 0; k < header->num_clauses; ++k) {
1244 MonoJitExceptionInfo *ei = &jinfo->clauses [k];
1246 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)
1247 fprintf (tmpfp, "\t.long %d\n", (guint8*)ei->data.filter - code);
1249 /* fixme: tokens are not global */
1250 fprintf (tmpfp, "\t.long %d\n", ei->data.token);
1252 fprintf (tmpfp, "\t.long %d\n", (guint8*)ei->try_start - code);
1253 fprintf (tmpfp, "\t.long %d\n", (guint8*)ei->try_end - code);
1254 fprintf (tmpfp, "\t.long %d\n", (guint8*)ei->handler_start - code);
1259 if (cfg->opt & MONO_OPT_SHARED) {
1260 fprintf (tmpfp, "\t.long %d\n", g_list_length (cfg->ldstr_list));
1261 for (l = cfg->ldstr_list; l; l = l->next) {
1262 fprintf (tmpfp, "\t.long 0x%08lx\n", (long)l->data);
1266 /* Used only in shared mode */
1267 g_assert (!cfg->ldstr_list);
1269 //printf ("M: %s (%s).\n", mono_method_full_name (method, TRUE), mname);
1272 guint32 last_offset;
1277 /* First emit the type+position table */
1278 for (pindex = 0; pindex < patches->len; ++pindex) {
1280 patch_info = g_ptr_array_index (patches, pindex);
1282 if ((patch_info->type == MONO_PATCH_INFO_LABEL) ||
1283 (patch_info->type == MONO_PATCH_INFO_BB))
1287 //printf ("T: %d O: %d.\n", patch_info->type, patch_info->ip.i);
1288 offset = patch_info->ip.i - last_offset;
1289 last_offset = patch_info->ip.i;
1291 /* Encode type+position compactly */
1292 g_assert (patch_info->type < 64);
1293 if (offset < 1024 - 1) {
1294 fprintf (tmpfp, "\t.byte %d\n", (patch_info->type << 2) + (offset >> 8));
1295 fprintf (tmpfp, "\t.byte %d\n", offset & ((1 << 8) - 1));
1298 fprintf (tmpfp, "\t.byte %d\n", (patch_info->type << 2) + 3);
1299 fprintf (tmpfp, "\t.byte %d\n", 255);
1300 emit_alignment(tmpfp, 4);
1301 fprintf (tmpfp, "\t.long %d\n", offset);
1306 * 0 is PATCH_INFO_BB, which can't be in the file.
1308 /* NULL terminated array */
1309 fprintf (tmpfp, "\t.byte 0\n");
1311 emit_alignment (tmpfp, sizeof (gpointer));
1313 /* Then emit the other info */
1314 for (pindex = 0; pindex < patches->len; ++pindex) {
1315 patch_info = g_ptr_array_index (patches, pindex);
1317 if ((patch_info->type == MONO_PATCH_INFO_LABEL) ||
1318 (patch_info->type == MONO_PATCH_INFO_BB))
1322 switch (patch_info->type) {
1323 case MONO_PATCH_INFO_METHODCONST:
1324 case MONO_PATCH_INFO_METHOD:
1325 case MONO_PATCH_INFO_METHOD_JUMP:
1326 case MONO_PATCH_INFO_CLASS:
1327 case MONO_PATCH_INFO_IID:
1328 case MONO_PATCH_INFO_FIELD:
1329 case MONO_PATCH_INFO_INTERNAL_METHOD:
1330 case MONO_PATCH_INFO_IMAGE:
1331 case MONO_PATCH_INFO_VTABLE:
1332 case MONO_PATCH_INFO_CLASS_INIT:
1333 case MONO_PATCH_INFO_SFLDA:
1334 case MONO_PATCH_INFO_EXC_NAME:
1335 emit_pointer (tmpfp, patch_info->data.name);
1338 case MONO_PATCH_INFO_SWITCH:
1339 case MONO_PATCH_INFO_R4:
1340 case MONO_PATCH_INFO_R8:
1341 case MONO_PATCH_INFO_METHOD_REL:
1342 case MONO_PATCH_INFO_LDSTR:
1343 case MONO_PATCH_INFO_LDTOKEN:
1344 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1345 case MONO_PATCH_INFO_WRAPPER: {
1347 sprintf (buf, "%s_p_%d", mname, j);
1348 emit_pointer (tmpfp, buf);
1352 case MONO_PATCH_INFO_LABEL:
1353 case MONO_PATCH_INFO_BB:
1356 g_warning ("unable to handle jump info %d", patch_info->type);
1357 g_assert_not_reached ();
1367 mono_debug_serialize_debug_info (cfg, &buf, &buf_len);
1369 fprintf (tmpfp, "\t.long %d\n", buf_len);
1371 for (i = 0; i < buf_len; ++i)
1372 fprintf (tmpfp, ".byte %d\n", (unsigned int) buf [i]);
1378 /* fixme: save the rest of the required infos */
1385 str_begins_with (const char *str1, const char *str2)
1387 int len = strlen (str2);
1388 return strncmp (str1, str2, len) == 0;
1392 mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts)
1394 gchar **args, **ptr;
1396 memset (opts, 0, sizeof (*opts));
1398 args = g_strsplit (aot_options ? aot_options : "", ",", -1);
1399 for (ptr = args; ptr && *ptr; ptr ++) {
1400 const char *arg = *ptr;
1402 if (str_begins_with (arg, "outfile=")) {
1403 opts->outfile = g_strdup (arg + strlen ("outfile="));
1406 fprintf (stderr, "AOT : Unknown argument '%s'.\n", arg);
1413 mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
1416 MonoImage *image = ass->image;
1418 char *com, *tmpfname, *opts_str;
1422 int ccount = 0, mcount = 0, lmfcount = 0, abscount = 0, wrappercount = 0, ocount = 0;
1423 GHashTable *ref_hash;
1424 MonoAotCompile *acfg;
1426 MonoAotOptions aot_opts;
1427 char *outfile_name, *tmp_outfile_name;
1429 printf ("Mono Ahead of Time compiler - compiling assembly %s\n", image->name);
1431 mono_aot_parse_options (aot_options, &aot_opts);
1433 i = g_file_open_tmp ("mono_aot_XXXXXX", &tmpfname, NULL);
1434 tmpfp = fdopen (i, "w+");
1437 ref_hash = g_hash_table_new (NULL, NULL);
1439 acfg = g_new0 (MonoAotCompile, 1);
1441 acfg->ref_hash = ref_hash;
1442 acfg->icall_hash = g_hash_table_new (NULL, NULL);
1443 acfg->icall_table = g_ptr_array_new ();
1444 acfg->image_hash = g_hash_table_new (NULL, NULL);
1445 acfg->image_table = g_ptr_array_new ();
1447 write_string_symbol (tmpfp, "mono_assembly_guid" , image->guid);
1449 write_string_symbol (tmpfp, "mono_aot_version", MONO_AOT_FILE_VERSION);
1451 opts_str = g_strdup_printf ("%d", opts);
1452 write_string_symbol (tmpfp, "mono_aot_opt_flags", opts_str);
1455 emitted = g_new0 (gboolean, image->tables [MONO_TABLE_METHOD].rows);
1457 for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
1458 MonoJumpInfo *patch_info;
1460 guint32 token = MONO_TOKEN_METHOD_DEF | (i + 1);
1461 method = mono_get_method (image, token, NULL);
1463 /* fixme: maybe we can also precompile wrapper methods */
1464 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
1465 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
1466 (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
1467 (method->flags & METHOD_ATTRIBUTE_ABSTRACT)) {
1468 //printf ("Skip (impossible): %s\n", mono_method_full_name (method, TRUE));
1474 /* fixme: we need to patch the IP for the LMF in that case */
1475 if (method->save_lmf) {
1476 //printf ("Skip (needs lmf): %s\n", mono_method_full_name (method, TRUE));
1481 //printf ("START: %s\n", mono_method_full_name (method, TRUE));
1482 //mono_compile_method (method);
1484 cfg = mini_method_compile (method, opts, mono_get_root_domain (), FALSE, 0);
1487 if (cfg->disable_aot) {
1488 printf ("Skip (other): %s\n", mono_method_full_name (method, TRUE));
1494 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
1495 if (patch_info->type == MONO_PATCH_INFO_ABS) {
1496 /* unable to handle this */
1497 //printf ("Skip (abs addr): %s %d\n", mono_method_full_name (method, TRUE), patch_info->type);
1508 /* some wrappers are very common */
1509 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
1510 if (patch_info->type == MONO_PATCH_INFO_METHODCONST) {
1511 switch (patch_info->data.method->wrapper_type) {
1512 case MONO_WRAPPER_PROXY_ISINST:
1513 patch_info->type = MONO_PATCH_INFO_WRAPPER;
1517 if (patch_info->type == MONO_PATCH_INFO_METHOD) {
1518 switch (patch_info->data.method->wrapper_type) {
1519 case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK:
1520 case MONO_WRAPPER_STFLD:
1521 case MONO_WRAPPER_LDFLD:
1522 patch_info->type = MONO_PATCH_INFO_WRAPPER;
1529 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
1530 if ((patch_info->type == MONO_PATCH_INFO_METHOD ||
1531 patch_info->type == MONO_PATCH_INFO_METHODCONST) &&
1532 patch_info->data.method->wrapper_type) {
1533 /* unable to handle this */
1534 //printf ("Skip (wrapper call): %s %d -> %s\n", mono_method_full_name (method, TRUE), patch_info->type, mono_method_full_name (patch_info->data.method, TRUE));
1545 //printf ("Compile: %s\n", mono_method_full_name (method, TRUE));
1548 emit_method (acfg, cfg);
1550 mono_destroy_compile (cfg);
1556 * The icall and image tables are small but referenced in a lot of places.
1557 * So we emit them at once, and reference their elements by an index
1558 * instead of an assembly label to cut back on the number of relocations.
1561 /* Emit icall table */
1563 symbol = g_strdup_printf ("mono_icall_table");
1564 emit_section_change (tmpfp, ".text", 1);
1565 emit_global(tmpfp, symbol);
1566 emit_alignment(tmpfp, 8);
1567 emit_label(tmpfp, symbol);
1568 fprintf (tmpfp, ".long %d\n", acfg->icall_table->len);
1569 for (i = 0; i < acfg->icall_table->len; i++)
1570 fprintf (tmpfp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, (char*)g_ptr_array_index (acfg->icall_table, i));
1572 /* Emit image table */
1574 symbol = g_strdup_printf ("mono_image_table");
1575 emit_section_change (tmpfp, ".text", 1);
1576 emit_global(tmpfp, symbol);
1577 emit_alignment(tmpfp, 8);
1578 emit_label(tmpfp, symbol);
1579 fprintf (tmpfp, ".long %d\n", acfg->image_table->len);
1580 for (i = 0; i < acfg->image_table->len; i++)
1581 fprintf (tmpfp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, ((MonoImage*)g_ptr_array_index (acfg->image_table, i))->guid);
1584 * g_module_symbol takes a lot of time for failed lookups, so we emit
1585 * a table which contains one bit for each method. This bit specifies
1586 * whenever the method is emitted or not.
1589 symbol = g_strdup_printf ("mono_methods_present_table");
1590 emit_section_change (tmpfp, ".text", 1);
1591 emit_global(tmpfp, symbol);
1592 emit_alignment(tmpfp, 8);
1593 emit_label(tmpfp, symbol);
1598 nrows = image->tables [MONO_TABLE_METHOD].rows;
1599 for (i = 0; i < nrows / 32 + 1; ++i) {
1601 for (k = 0; k < 32; ++k) {
1602 if (emitted [(i * 32) + k])
1605 //printf ("EMITTED [%d] = %d.\n", i, b);
1606 fprintf (tmpfp, "\t.long %d\n", w);
1612 #if defined(sparc) && SIZEOF_VOID_P == 8
1613 com = g_strdup_printf ("as -xarch=v9 %s -o %s.o", tmpfname, tmpfname);
1615 com = g_strdup_printf ("as %s -o %s.o", tmpfname, tmpfname);
1617 printf ("Executing the native assembler: %s\n", com);
1618 if (system (com) != 0) {
1625 if (aot_opts.outfile)
1626 outfile_name = g_strdup_printf ("%s", aot_opts.outfile);
1628 outfile_name = g_strdup_printf ("%s%s", image->name, SHARED_EXT);
1630 tmp_outfile_name = g_strdup_printf ("%s.tmp", outfile_name);
1633 com = g_strdup_printf ("ld -shared -G -o %s %s.o", outfile_name, tmpfname);
1634 #elif defined(__ppc__) && defined(__MACH__)
1635 com = g_strdup_printf ("gcc -dynamiclib -o %s %s.o", outfile_name, tmpfname);
1637 com = g_strdup_printf ("ld -shared -o %s %s.o", outfile_name, tmpfname);
1639 printf ("Executing the native linker: %s\n", com);
1640 if (system (com) != 0) {
1641 g_free (tmp_outfile_name);
1642 g_free (outfile_name);
1648 com = g_strdup_printf ("%s.o", tmpfname);
1651 /*com = g_strdup_printf ("strip --strip-unneeded %s%s", image->name, SHARED_EXT);
1652 printf ("Stripping the binary: %s\n", com);
1656 rename (tmp_outfile_name, outfile_name);
1658 g_free (tmp_outfile_name);
1659 g_free (outfile_name);
1661 printf ("Compiled %d out of %d methods (%d%%)\n", ccount, mcount, mcount ? (ccount*100)/mcount : 100);
1662 printf ("%d methods contain absolute addresses (%d%%)\n", abscount, mcount ? (abscount*100)/mcount : 100);
1663 printf ("%d methods contain wrapper references (%d%%)\n", wrappercount, mcount ? (wrappercount*100)/mcount : 100);
1664 printf ("%d methods contain lmf pointers (%d%%)\n", lmfcount, mcount ? (lmfcount*100)/mcount : 100);
1665 printf ("%d methods have other problems (%d%%)\n", ocount, mcount ? (ocount*100)/mcount : 100);
1666 //printf ("Retained input file.\n");