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 err = mkdir (tmp, 0777);
149 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT failed: %s", g_strerror (errno));
155 tmp = g_build_filename (home, ".mono", "aot-cache", NULL);
156 if (!g_file_test (tmp, G_FILE_TEST_IS_DIR)) {
157 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT creating directory %s", tmp);
158 err = mkdir (tmp, 0777);
160 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT failed: %s", g_strerror (errno));
169 * load_aot_module_from_cache:
171 * Experimental code to AOT compile loaded assemblies on demand.
174 * - Add environment variable MONO_AOT_CACHE_OPTIONS
175 * - Add options for controlling the cache size
176 * - Handle full cache by deleting old assemblies lru style
177 * - Add options for excluding assemblies during development
178 * - Maybe add a threshold after an assembly is AOT compiled
179 * - invoking a new mono process is a security risk
182 load_aot_module_from_cache (MonoAssembly *assembly, char **aot_name)
184 char *fname, *cmd, *tmp2;
192 if (assembly->image->dynamic)
195 create_cache_structure ();
197 home = g_get_home_dir ();
199 tmp2 = g_strdup_printf ("%s-%s%s", assembly->image->assembly_name, assembly->image->guid, SHARED_EXT);
200 fname = g_build_filename (home, ".mono", "aot-cache", tmp2, NULL);
204 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT trying to load from cache: '%s'.", fname);
205 module = g_module_open (fname, G_MODULE_BIND_LAZY);
208 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT not found.");
210 mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT precompiling assembly '%s'... ", assembly->image->name);
212 /* FIXME: security */
213 cmd = g_strdup_printf ("mono -O=all --aot=outfile=%s %s", fname, assembly->image->name);
215 res = g_spawn_command_line_sync (cmd, &out, &err, NULL, NULL);
218 mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT failed.");
222 mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT succeeded.");
224 module = g_module_open (fname, G_MODULE_BIND_LAZY);
231 load_aot_module (MonoAssembly *assembly, gpointer user_data)
235 gboolean usable = TRUE;
236 char *saved_guid = NULL;
237 char *aot_version = NULL;
238 char *opt_flags = NULL;
240 if (mono_compile_aot)
244 assembly->aot_module = load_aot_module_from_cache (assembly, &aot_name);
246 aot_name = g_strdup_printf ("%s%s", assembly->image->name, SHARED_EXT);
248 assembly->aot_module = g_module_open (aot_name, G_MODULE_BIND_LAZY);
250 if (!assembly->aot_module) {
251 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT failed to load AOT module %s: %s\n", aot_name, g_module_error ());
255 if (!assembly->aot_module) {
260 g_module_symbol (assembly->aot_module, "mono_assembly_guid", (gpointer *) &saved_guid);
261 g_module_symbol (assembly->aot_module, "mono_aot_version", (gpointer *) &aot_version);
262 g_module_symbol (assembly->aot_module, "mono_aot_opt_flags", (gpointer *)&opt_flags);
264 if (!aot_version || strcmp (aot_version, MONO_AOT_FILE_VERSION)) {
265 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);
269 if (!saved_guid || strcmp (assembly->image->guid, saved_guid)) {
270 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT module %s is out of date.\n", aot_name);
276 g_module_close (assembly->aot_module);
277 assembly->aot_module = NULL;
282 * It seems that MonoGHashTables are in the GC heap, so structures
283 * containing them must be in the GC heap as well :(
286 info = GC_MALLOC (sizeof (MonoAotModule));
288 info = g_new0 (MonoAotModule, 1);
290 info->methods = mono_g_hash_table_new (NULL, NULL);
291 sscanf (opt_flags, "%d", &info->opts);
293 /* Read image table */
295 guint32 table_len, i;
298 g_module_symbol (assembly->aot_module, "mono_image_table", (gpointer *)&table);
301 table_len = *(guint32*)table;
302 table += sizeof (guint32);
303 info->image_table = g_new0 (MonoImage*, table_len);
304 for (i = 0; i < table_len; ++i) {
305 info->image_table [i] = mono_image_loaded_by_guid (table);
306 if (!info->image_table [i]) {
307 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT module %s is out of date.\n", aot_name);
308 mono_g_hash_table_destroy (info->methods);
309 g_free (info->image_table);
310 #ifndef HAVE_BOEHM_GC
314 g_module_close (assembly->aot_module);
315 assembly->aot_module = NULL;
318 table += strlen (table) + 1;
322 /* Read icall table */
324 guint32 table_len, i;
327 g_module_symbol (assembly->aot_module, "mono_icall_table", (gpointer *)&table);
330 table_len = *(guint32*)table;
331 table += sizeof (guint32);
332 info->icall_table = g_new0 (char*, table_len);
333 for (i = 0; i < table_len; ++i) {
334 info->icall_table [i] = table;
335 table += strlen (table) + 1;
339 /* Read methods present table */
340 g_module_symbol (assembly->aot_module, "mono_methods_present_table", (gpointer *)&info->methods_present_table);
341 g_assert (info->methods_present_table);
343 EnterCriticalSection (&aot_mutex);
344 mono_g_hash_table_insert (aot_modules, assembly, info);
345 LeaveCriticalSection (&aot_mutex);
347 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT loaded AOT Module for %s.\n", assembly->image->name);
353 InitializeCriticalSection (&aot_mutex);
355 aot_modules = mono_g_hash_table_new (NULL, NULL);
357 mono_install_assembly_load_hook (load_aot_module, NULL);
359 if (getenv ("MONO_LASTAOT"))
360 mono_last_aot_method = atoi (getenv ("MONO_LASTAOT"));
364 mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method)
366 MonoClass *klass = method->klass;
367 MonoAssembly *ass = klass->image->assembly;
368 GModule *module = ass->aot_module;
369 char method_label [256];
370 char info_label [256];
373 MonoAotModule *aot_module;
374 MonoAotMethod *minfo;
376 MonoMethodHeader *header = ((MonoMethodNormal*)method)->header;
385 if (mono_profiler_get_events () & MONO_PROFILE_ENTER_LEAVE)
388 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
389 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
390 (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
391 (method->flags & METHOD_ATTRIBUTE_ABSTRACT))
394 aot_module = (MonoAotModule*)mono_g_hash_table_lookup (aot_modules, ass);
396 g_assert (klass->inited);
398 minfo = mono_g_hash_table_lookup (aot_module->methods, method);
399 /* Can't use code from non-root domains since they can be unloaded */
400 if (minfo && (minfo->domain == mono_get_root_domain ())) {
401 /* This method was already loaded in another appdomain */
403 /* Duplicate jinfo */
404 jinfo = mono_mempool_alloc0 (domain->mp, sizeof (MonoJitInfo));
405 memcpy (jinfo, minfo->info, sizeof (MonoJitInfo));
406 if (jinfo->clauses) {
408 mono_mempool_alloc0 (domain->mp, sizeof (MonoJitExceptionInfo) * header->num_clauses);
409 memcpy (jinfo->clauses, minfo->info->clauses, sizeof (MonoJitExceptionInfo) * header->num_clauses);
412 if (aot_module->opts & MONO_OPT_SHARED)
413 /* Use the same method in the new appdomain */
415 else if (!minfo->patch_info)
416 /* Use the same method in the new appdomain */
419 /* Create a copy of the original method and apply relocations */
421 code = mono_code_manager_reserve (domain->code_mp, minfo->info->code_size);
422 memcpy (code, minfo->info->code_start, minfo->info->code_size);
424 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);
426 /* Do this outside the lock to avoid deadlocks */
427 LeaveCriticalSection (&aot_mutex);
428 mono_arch_patch_code (method, domain, code, minfo->patch_info, TRUE);
429 EnterCriticalSection (&aot_mutex);
430 mono_arch_flush_icache (code, minfo->info->code_size);
433 jinfo->code_start = code;
434 if (jinfo->clauses) {
435 for (i = 0; i < header->num_clauses; ++i) {
436 MonoJitExceptionInfo *ei = &jinfo->clauses [i];
437 gint32 offset = code - (guint8*)minfo->info->code_start;
439 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)
440 ei->data.filter = (guint8*)ei->data.filter + offset;
441 ei->try_start = (guint8*)ei->try_start + offset;
442 ei->try_end = (guint8*)ei->try_end + offset;
443 ei->handler_start = (guint8*)ei->handler_start + offset;
451 /* Do a fast check to see whenever the method exists */
453 guint32 index = mono_metadata_token_index (method->token) - 1;
455 w = aot_module->methods_present_table [index / 32];
456 if (! (w & (1 << (index % 32)))) {
457 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT NOT FOUND: %s.\n", mono_method_full_name (method, TRUE));
462 sprintf (method_label, "m_%x", mono_metadata_token_index (method->token));
464 if (!g_module_symbol (module, method_label, (gpointer *)&code))
467 sprintf (info_label, "%s_p", method_label);
469 if (!g_module_symbol (module, info_label, (gpointer *)&info))
472 if (mono_last_aot_method != -1) {
473 if (mono_jit_stats.methods_aot > mono_last_aot_method)
476 if (mono_jit_stats.methods_aot == mono_last_aot_method)
477 printf ("LAST AOT METHOD: %s.%s.%s.\n", klass->name_space, klass->name, method->name);
480 return mono_aot_load_method (domain, aot_module, method, code, info);
484 mono_aot_load_method (MonoDomain *domain, MonoAotModule *aot_module, MonoMethod *method, guint8 *code, guint8 *info)
486 MonoClass *klass = method->klass;
487 MonoJumpInfo *patch_info = NULL;
488 guint code_len, used_int_regs, used_strings;
489 MonoAotMethod *minfo;
491 MonoMethodHeader *header = ((MonoMethodNormal*)method)->header;
496 minfo = GC_MALLOC (sizeof (MonoAotMethod));
498 minfo = g_new0 (MonoAotMethod, 1);
501 minfo->domain = domain;
502 jinfo = mono_mempool_alloc0 (domain->mp, sizeof (MonoJitInfo));
504 code_len = *(guint32*)info;
506 used_int_regs = *(guint32*)info;
509 if (!use_loaded_code) {
511 code2 = mono_code_manager_reserve (domain->code_mp, code_len);
512 memcpy (code2, code, code_len);
513 mono_arch_flush_icache (code2, code_len);
517 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);
519 /* Exception table */
520 if (header->num_clauses) {
522 mono_mempool_alloc0 (domain->mp, sizeof (MonoJitExceptionInfo) * header->num_clauses);
523 jinfo->num_clauses = header->num_clauses;
525 jinfo->exvar_offset = *(guint32*)info;
528 for (i = 0; i < header->num_clauses; ++i) {
529 MonoExceptionClause *ec = &header->clauses [i];
530 MonoJitExceptionInfo *ei = &jinfo->clauses [i];
532 ei->flags = ec->flags;
533 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)
534 ei->data.filter = code + *(guint32*)info;
536 ei->data.token = *(guint32*)info;
538 ei->try_start = code + *(guint32*)info;
540 ei->try_end = code + *(guint32*)info;
542 ei->handler_start = code + *(guint32*)info;
547 if (aot_module->opts & MONO_OPT_SHARED) {
548 used_strings = *(guint32*)info;
554 for (i = 0; i < used_strings; i++) {
555 guint token = *(guint32*)info;
557 mono_ldstr (mono_get_root_domain (), klass->image, mono_metadata_token_index (token));
567 guint32 last_offset, buf_len;
570 if (aot_module->opts & MONO_OPT_SHARED)
571 mp = mono_mempool_new ();
575 /* First load the type + offset table */
577 patches = g_ptr_array_new ();
579 MonoJumpInfo *ji = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
584 b2 = *((guint8*)info + 1);
590 if (((b1 & (1 + 2)) == 3) && (b2 == 255)) {
591 info = ALIGN_PTR_TO (info, 4);
592 ji->ip.i = *(guint32*)info;
596 ji->ip.i = (((guint32)(b1 & (1 + 2))) << 8) + b2;
598 ji->ip.i += last_offset;
599 last_offset = ji->ip.i;
600 //printf ("T: %d O: %d.\n", ji->type, ji->ip.i);
602 ji->next = patch_info;
605 g_ptr_array_add (patches, ji);
609 info = ALIGN_PTR_TO (info, sizeof (gpointer));
611 /* Then load the other data */
612 for (pindex = 0; pindex < patches->len; ++pindex) {
613 MonoJumpInfo *ji = g_ptr_array_index (patches, pindex);
615 data = *((guint32 **)info);
616 info += sizeof (gpointer);
619 case MONO_PATCH_INFO_CLASS:
620 case MONO_PATCH_INFO_IID:
621 ji->data.klass = decode_class_info (aot_module, data);
622 g_assert (ji->data.klass);
623 mono_class_init (ji->data.klass);
625 case MONO_PATCH_INFO_VTABLE:
626 case MONO_PATCH_INFO_CLASS_INIT:
627 ji->data.klass = decode_class_info (aot_module, data);
628 g_assert (ji->data.klass);
629 mono_class_init (ji->data.klass);
631 case MONO_PATCH_INFO_IMAGE:
632 ji->data.image = aot_module->image_table [(guint32)data];
633 g_assert (ji->data.image);
635 case MONO_PATCH_INFO_METHOD:
636 case MONO_PATCH_INFO_METHODCONST:
637 case MONO_PATCH_INFO_METHOD_JUMP: {
638 guint32 image_index, token;
640 image_index = (guint32)data >> 24;
641 token = MONO_TOKEN_METHOD_DEF | ((guint32)data & 0xffffff);
643 image = aot_module->image_table [image_index];
644 ji->data.method = mono_get_method (image, token, NULL);
645 g_assert (ji->data.method);
646 mono_class_init (ji->data.method->klass);
650 case MONO_PATCH_INFO_WRAPPER: {
651 guint32 wrapper_type;
653 wrapper_type = (guint32)data[0];
655 switch (wrapper_type) {
656 case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK: {
657 guint32 image_index, token;
659 image_index = (guint32)data[1] >> 24;
660 token = MONO_TOKEN_METHOD_DEF | ((guint32)data[1] & 0xffffff);
662 image = aot_module->image_table [image_index];
663 ji->data.method = mono_get_method (image, token, NULL);
664 g_assert (ji->data.method);
665 mono_class_init (ji->data.method->klass);
667 ji->type = MONO_PATCH_INFO_METHOD;
668 ji->data.method = mono_marshal_get_remoting_invoke_with_check (ji->data.method);
671 case MONO_WRAPPER_PROXY_ISINST: {
672 /* The pointer is dword aligned */
673 gpointer class_ptr = *(gpointer*)(ALIGN_PTR_TO (&data[1], sizeof (gpointer)));
674 MonoClass *klass = decode_class_info (aot_module, class_ptr);
675 mono_class_init (klass);
676 ji->type = MONO_PATCH_INFO_METHODCONST;
677 ji->data.method = mono_marshal_get_proxy_cancast (klass);
680 case MONO_WRAPPER_LDFLD:
681 case MONO_WRAPPER_STFLD: {
682 /* The pointer is dword aligned */
683 gpointer class_ptr = *(gpointer*)(ALIGN_PTR_TO (&data[1], sizeof (gpointer)));
684 MonoClass *klass = decode_class_info (aot_module, class_ptr);
685 mono_class_init (klass);
686 ji->type = MONO_PATCH_INFO_METHOD;
687 if (wrapper_type == MONO_WRAPPER_LDFLD)
688 ji->data.method = mono_marshal_get_ldfld_wrapper (&klass->byval_arg);
690 ji->data.method = mono_marshal_get_stfld_wrapper (&klass->byval_arg);
694 g_assert_not_reached ();
698 case MONO_PATCH_INFO_FIELD:
699 case MONO_PATCH_INFO_SFLDA: {
700 /* The pointer is dword aligned */
701 gpointer class_ptr = *(gpointer*)(ALIGN_PTR_TO (&data[1], sizeof (gpointer)));
702 MonoClass *klass = decode_class_info (aot_module, class_ptr);
703 mono_class_init (klass);
704 ji->data.field = mono_class_get_field (klass, data [0]);
707 case MONO_PATCH_INFO_INTERNAL_METHOD:
708 ji->data.name = aot_module->icall_table [(guint32)data];
709 g_assert (ji->data.name);
710 //printf ("A: %s.\n", ji->data.name);
712 case MONO_PATCH_INFO_SWITCH:
713 ji->table_size = data [0];
714 table = g_new (gpointer, ji->table_size);
715 ji->data.target = table;
716 for (i = 0; i < ji->table_size; i++) {
717 table [i] = (gpointer)data [i + 1];
720 case MONO_PATCH_INFO_R4:
721 case MONO_PATCH_INFO_R8:
722 ji->data.target = data;
724 case MONO_PATCH_INFO_LDSTR:
725 case MONO_PATCH_INFO_LDTOKEN:
726 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
727 image = aot_module->image_table [data [0]];
728 ji->data.token = mono_jump_info_token_new (mp, image, data [1]);
730 case MONO_PATCH_INFO_EXC_NAME:
731 ji->data.klass = decode_class_info (aot_module, data);
732 g_assert (ji->data.klass);
733 mono_class_init (ji->data.klass);
734 ji->data.name = ji->data.klass->name;
736 case MONO_PATCH_INFO_METHOD_REL:
737 ji->data.offset = data [0];
740 g_warning ("unhandled type %d", ji->type);
741 g_assert_not_reached ();
745 g_ptr_array_free (patches, TRUE);
747 buf_len = *(guint32*)info;
749 mono_debug_add_aot_method (domain, method, code, info, buf_len);
751 if (use_loaded_code) {
752 /* disable write protection */
753 #ifndef PLATFORM_WIN32
754 page_start = (char *) (((int) (code)) & ~ (PAGESIZE - 1));
755 pages = (code + code_len - page_start + PAGESIZE - 1) / PAGESIZE;
756 err = mprotect (page_start, pages * PAGESIZE, PROT_READ | PROT_WRITE | PROT_EXEC);
761 g_assert (VirtualProtect (code, code_len, PAGE_EXECUTE_READWRITE, &oldp) != 0);
766 /* Do this outside the lock to avoid deadlocks */
767 LeaveCriticalSection (&aot_mutex);
768 mono_arch_patch_code (method, domain, code, patch_info, TRUE);
769 EnterCriticalSection (&aot_mutex);
771 if (aot_module->opts & MONO_OPT_SHARED)
772 /* No need to cache patches */
773 mono_mempool_destroy (mp);
775 minfo->patch_info = patch_info;
778 mono_jit_stats.methods_aot++;
781 jinfo->code_size = code_len;
782 jinfo->used_regs = used_int_regs;
783 jinfo->method = method;
784 jinfo->code_start = code;
785 jinfo->domain_neutral = (aot_module->opts & MONO_OPT_SHARED) != 0;
788 mono_g_hash_table_insert (aot_module->methods, method, minfo);
795 mono_aot_get_method (MonoDomain *domain, MonoMethod *method)
799 EnterCriticalSection (&aot_mutex);
800 info = mono_aot_get_method_inner (domain, method);
801 LeaveCriticalSection (&aot_mutex);
803 /* Do this outside the lock */
805 mono_jit_info_table_add (domain, info);
813 emit_section_change (FILE *fp, const char *section_name, int subsection_index)
816 /* For solaris as, GNU as should accept the same */
817 fprintf (fp, ".section \"%s\"\n", section_name);
818 #elif defined(__ppc__) && defined(__MACH__)
819 /* This needs to be made more precise on mach. */
820 fprintf (fp, "%s\n", subsection_index == 0 ? ".text" : ".data");
822 fprintf (fp, "%s %d\n", section_name, subsection_index);
827 emit_global (FILE *fp, const char *name)
829 #if defined(__ppc__) && defined(__MACH__)
830 // mach-o always uses a '_' prefix.
831 fprintf (fp, ".globl _%s\n", name);
833 fprintf (fp, ".globl %s\n", name);
838 emit_label (FILE *fp, const char *name)
840 #if defined(__ppc__) && defined(__MACH__)
841 // mach-o always uses a '_' prefix.
842 fprintf (fp, "_%s:\n", name);
844 fprintf (fp, "%s:\n", name);
850 write_data_symbol (FILE *fp, const char *name, guint8 *buf, int size, int align)
854 emit_section_change (fp, ".text", 1);
856 fprintf (fp, ".globl %s\n", name);
857 fprintf (fp, "\t.align %d\n", align);
858 fprintf (fp, "\t.type %s,#object\n", name);
859 fprintf (fp, "\t.size %s,%d\n", name, size);
860 fprintf (fp, "%s:\n", name);
861 for (i = 0; i < size; i++) {
862 fprintf (fp, ".byte %d\n", buf [i]);
869 write_string_symbol (FILE *fp, const char *name, const char *value)
871 emit_section_change (fp, ".text", 1);
872 emit_global(fp, name);
873 emit_label(fp, name);
874 fprintf (fp, "\t%s \"%s\"\n", AS_STRING_DIRECTIVE, value);
878 mono_get_field_token (MonoClassField *field)
880 MonoClass *klass = field->parent;
883 for (i = 0; i < klass->field.count; ++i) {
884 if (field == &klass->fields [i])
885 return MONO_TOKEN_FIELD_DEF | (klass->field.first + 1 + i);
888 g_assert_not_reached ();
893 get_image_index (MonoAotCompile *cfg, MonoImage *image)
897 index = GPOINTER_TO_UINT (g_hash_table_lookup (cfg->image_hash, image));
901 index = g_hash_table_size (cfg->image_hash);
902 g_hash_table_insert (cfg->image_hash, image, GUINT_TO_POINTER (index + 1));
903 g_ptr_array_add (cfg->image_table, image);
909 emit_image_index (MonoAotCompile *cfg, MonoImage *image)
913 image_index = get_image_index (cfg, image);
915 fprintf (cfg->fp, "\t.long %d\n", image_index);
918 #if defined(__ppc__) && defined(__MACH__)
920 ilog2(register int value)
923 while (value & ~0xf) count += 4, value >>= 4;
924 while (value) count++, value >>= 1;
929 static void emit_alignment(FILE *fp, int size)
931 #if defined(__ppc__) && defined(__MACH__)
932 // the mach-o assembler specifies alignments as powers of 2.
933 fprintf (fp, "\t.align %d\t; ilog2\n", ilog2(size));
934 #elif defined(__powerpc__)
935 /* ignore on linux/ppc */
937 fprintf (fp, "\t.align %d\n", size);
942 emit_pointer (FILE *fp, const char *target)
944 emit_alignment (fp, sizeof (gpointer));
945 #if defined(sparc) && SIZEOF_VOID_P == 8
946 fprintf (fp, "\t.xword %s\n", target);
948 fprintf (fp, "\t.long %s\n", target);
953 cond_emit_klass_label (MonoAotCompile *cfg, MonoClass *klass)
955 char *l1, *el = NULL;
957 if ((l1 = g_hash_table_lookup (cfg->ref_hash, klass)))
960 if (!klass->type_token) {
961 g_assert (klass->rank > 0);
962 el = cond_emit_klass_label (cfg, klass->element_class);
965 emit_alignment(cfg->fp, sizeof (gpointer));
967 l1 = g_strdup_printf ("klass_p_%08x_%p", klass->type_token, klass);
968 fprintf (cfg->fp, "%s:\n", l1);
969 fprintf (cfg->fp, "\t.long 0x%08x\n", klass->type_token);
970 emit_image_index (cfg, klass->image);
973 fprintf (cfg->fp, "\t.long %d\n", klass->rank);
974 emit_pointer (cfg->fp, el);
977 g_hash_table_insert (cfg->ref_hash, klass, l1);
983 cond_emit_field_label (MonoAotCompile *cfg, MonoJumpInfo *patch_info)
985 MonoClassField *field = patch_info->data.field;
989 if ((l1 = g_hash_table_lookup (cfg->ref_hash, field)))
992 l2 = cond_emit_klass_label (cfg, field->parent);
993 emit_alignment(cfg->fp, sizeof (gpointer));
994 token = mono_get_field_token (field);
996 l1 = g_strdup_printf ("klass_p_%08x_%p", token, field);
997 fprintf (cfg->fp, "%s:\n", l1);
998 fprintf (cfg->fp, "\t.long 0x%08x\n", token);
999 emit_pointer (cfg->fp, l2);
1001 g_hash_table_insert (cfg->ref_hash, field, l1);
1007 compare_patches (gconstpointer a, gconstpointer b)
1011 i = (*(MonoJumpInfo**)a)->ip.i;
1012 j = (*(MonoJumpInfo**)b)->ip.i;
1024 emit_method (MonoAotCompile *acfg, MonoCompile *cfg)
1029 int i, j, k, pindex;
1030 guint8 *code, *mname, *mname_p;
1031 int func_alignment = 16;
1033 MonoJumpInfo *patch_info;
1034 MonoMethodHeader *header;
1037 method = cfg->method;
1038 code = cfg->native_code;
1039 header = ((MonoMethodNormal*)method)->header;
1041 emit_section_change (tmpfp, ".text", 0);
1042 mname = g_strdup_printf ("m_%x", mono_metadata_token_index (method->token));
1043 mname_p = g_strdup_printf ("%s_p", mname);
1044 emit_alignment(tmpfp, func_alignment);
1045 emit_global(tmpfp, mname);
1047 fprintf (tmpfp, "\t.type %s,#function\n", mname);
1048 #elif !(defined(__ppc__) && defined(__MACH__))
1049 fprintf (tmpfp, "\t.type %s,@function\n", mname);
1051 emit_label(tmpfp, mname);
1053 for (i = 0; i < cfg->code_len; i++)
1054 fprintf (tmpfp, ".byte %d\n", (unsigned int) code [i]);
1056 emit_section_change (tmpfp, ".text", 1);
1058 /* Sort relocations */
1059 patches = g_ptr_array_new ();
1060 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next)
1061 g_ptr_array_add (patches, patch_info);
1062 g_ptr_array_sort (patches, compare_patches);
1064 /* Emit out of line info for relocations */
1066 for (pindex = 0; pindex < patches->len; ++pindex) {
1067 patch_info = g_ptr_array_index (patches, pindex);
1068 switch (patch_info->type) {
1069 case MONO_PATCH_INFO_LABEL:
1070 case MONO_PATCH_INFO_BB:
1071 /* relative jumps are no problem, there is no need to handle then here */
1073 case MONO_PATCH_INFO_SWITCH: {
1074 gpointer *table = (gpointer *)patch_info->data.target;
1077 emit_alignment(tmpfp, sizeof (gpointer));
1078 fprintf (tmpfp, "%s_p_%d:\n", mname, j);
1079 fprintf (tmpfp, "\t.long %d\n", patch_info->table_size);
1081 for (k = 0; k < patch_info->table_size; k++) {
1082 fprintf (tmpfp, "\t.long %d\n", (int)table [k]);
1087 case MONO_PATCH_INFO_INTERNAL_METHOD: {
1088 guint32 icall_index;
1090 icall_index = (guint32)g_hash_table_lookup (acfg->icall_hash, patch_info->data.name);
1092 icall_index = g_hash_table_size (acfg->icall_hash) + 1;
1093 g_hash_table_insert (acfg->icall_hash, (gpointer)patch_info->data.name,
1094 GUINT_TO_POINTER (icall_index));
1095 g_ptr_array_add (acfg->icall_table, (gpointer)patch_info->data.name);
1097 patch_info->data.name = g_strdup_printf ("%d", icall_index - 1);
1101 case MONO_PATCH_INFO_METHODCONST:
1102 case MONO_PATCH_INFO_METHOD:
1103 case MONO_PATCH_INFO_METHOD_JUMP: {
1105 * The majority of patches are for methods, so we emit
1106 * them inline instead of defining a label for them to
1107 * decrease the number of relocations.
1109 guint32 image_index = get_image_index (acfg, patch_info->data.method->klass->image);
1110 guint32 token = patch_info->data.method->token;
1111 g_assert (image_index < 256);
1112 g_assert (mono_metadata_token_table (token) == MONO_TABLE_METHOD);
1114 patch_info->data.name =
1115 g_strdup_printf ("%d", (image_index << 24) + (mono_metadata_token_index (token)));
1119 case MONO_PATCH_INFO_WRAPPER: {
1120 switch (patch_info->data.method->wrapper_type) {
1121 case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK: {
1123 guint32 image_index;
1126 m = mono_marshal_method_from_wrapper (patch_info->data.method);
1127 image_index = get_image_index (acfg, m->klass->image);
1129 g_assert (image_index < 256);
1130 g_assert (mono_metadata_token_table (token) == MONO_TABLE_METHOD);
1131 emit_alignment(tmpfp, sizeof (gpointer));
1132 fprintf (tmpfp, "%s_p_%d:\n", mname, j);
1133 fprintf (tmpfp, "\t.long %d\n", patch_info->data.method->wrapper_type);
1134 fprintf (tmpfp, "\t.long %d\n", (image_index << 24) + (mono_metadata_token_index (token)));
1137 case MONO_WRAPPER_PROXY_ISINST:
1138 case MONO_WRAPPER_LDFLD:
1139 case MONO_WRAPPER_STFLD: {
1140 MonoClass *proxy_class = (MonoClass*)mono_marshal_method_from_wrapper (patch_info->data.method);
1141 char *klass_label = cond_emit_klass_label (acfg, proxy_class);
1143 fprintf (tmpfp, "%s_p_%d:\n", mname, j);
1144 fprintf (tmpfp, "\t.long %d\n", patch_info->data.method->wrapper_type);
1145 emit_pointer (tmpfp, klass_label);
1149 g_assert_not_reached ();
1154 case MONO_PATCH_INFO_FIELD:
1155 patch_info->data.name = cond_emit_field_label (acfg, patch_info);
1158 case MONO_PATCH_INFO_CLASS:
1159 case MONO_PATCH_INFO_IID:
1160 patch_info->data.name = cond_emit_klass_label (acfg, patch_info->data.klass);
1163 case MONO_PATCH_INFO_IMAGE:
1164 patch_info->data.name = g_strdup_printf ("%d", get_image_index (acfg, patch_info->data.image));
1167 case MONO_PATCH_INFO_EXC_NAME: {
1168 MonoClass *ex_class;
1171 mono_class_from_name (mono_defaults.exception_class->image,
1172 "System", patch_info->data.target);
1173 g_assert (ex_class);
1174 patch_info->data.name = cond_emit_klass_label (acfg, ex_class);
1178 case MONO_PATCH_INFO_R4:
1179 emit_alignment(tmpfp, 8);
1180 fprintf (tmpfp, "%s_p_%d:\n", mname, j);
1181 fprintf (tmpfp, "\t.long 0x%08x\n", *((guint32 *)patch_info->data.target));
1184 case MONO_PATCH_INFO_R8:
1185 emit_alignment(tmpfp, 8);
1186 fprintf (tmpfp, "%s_p_%d:\n", mname, j);
1187 fprintf (tmpfp, "\t.long 0x%08x\n", *((guint32 *)patch_info->data.target));
1188 fprintf (tmpfp, "\t.long 0x%08x\n", *((guint32 *)patch_info->data.target + 1));
1191 case MONO_PATCH_INFO_METHOD_REL:
1192 emit_alignment(tmpfp, sizeof (gpointer));
1193 fprintf (tmpfp, "%s_p_%d:\n", mname, j);
1194 fprintf (tmpfp, "\t.long 0x%08x\n", patch_info->data.offset);
1197 case MONO_PATCH_INFO_VTABLE:
1198 case MONO_PATCH_INFO_CLASS_INIT:
1199 patch_info->data.name = cond_emit_klass_label (acfg, patch_info->data.klass);
1202 case MONO_PATCH_INFO_SFLDA:
1203 patch_info->data.name = cond_emit_field_label (acfg, patch_info);
1206 case MONO_PATCH_INFO_LDSTR:
1207 case MONO_PATCH_INFO_LDTOKEN:
1208 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1209 emit_alignment(tmpfp, 8);
1210 fprintf (tmpfp, "%s_p_%d:\n", mname, j);
1211 fprintf (tmpfp, "\t.long 0x%08x\n", get_image_index (acfg, patch_info->data.token->image));
1212 fprintf (tmpfp, "\t.long 0x%08x\n", patch_info->data.token->token);
1216 g_warning ("unable to handle jump info %d", patch_info->type);
1217 g_assert_not_reached ();
1221 emit_global (tmpfp, mname_p);
1222 emit_alignment (tmpfp, sizeof (gpointer));
1223 emit_label (tmpfp, mname_p);
1225 fprintf (tmpfp, "\t.long %d\n", cfg->code_len);
1226 fprintf (tmpfp, "\t.long %ld\n", (long)cfg->used_int_regs);
1228 /* Exception table */
1229 if (header->num_clauses) {
1230 MonoJitInfo *jinfo = cfg->jit_info;
1232 fprintf (tmpfp, "\t.long %d\n", jinfo->exvar_offset);
1234 for (k = 0; k < header->num_clauses; ++k) {
1235 MonoJitExceptionInfo *ei = &jinfo->clauses [k];
1237 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)
1238 fprintf (tmpfp, "\t.long %d\n", (guint8*)ei->data.filter - code);
1240 /* fixme: tokens are not global */
1241 fprintf (tmpfp, "\t.long %d\n", ei->data.token);
1243 fprintf (tmpfp, "\t.long %d\n", (guint8*)ei->try_start - code);
1244 fprintf (tmpfp, "\t.long %d\n", (guint8*)ei->try_end - code);
1245 fprintf (tmpfp, "\t.long %d\n", (guint8*)ei->handler_start - code);
1250 if (cfg->opt & MONO_OPT_SHARED) {
1251 fprintf (tmpfp, "\t.long %d\n", g_list_length (cfg->ldstr_list));
1252 for (l = cfg->ldstr_list; l; l = l->next) {
1253 fprintf (tmpfp, "\t.long 0x%08lx\n", (long)l->data);
1257 /* Used only in shared mode */
1258 g_assert (!cfg->ldstr_list);
1260 //printf ("M: %s (%s).\n", mono_method_full_name (method, TRUE), mname);
1263 guint32 last_offset;
1268 /* First emit the type+position table */
1269 for (pindex = 0; pindex < patches->len; ++pindex) {
1271 patch_info = g_ptr_array_index (patches, pindex);
1273 if ((patch_info->type == MONO_PATCH_INFO_LABEL) ||
1274 (patch_info->type == MONO_PATCH_INFO_BB))
1278 //printf ("T: %d O: %d.\n", patch_info->type, patch_info->ip.i);
1279 offset = patch_info->ip.i - last_offset;
1280 last_offset = patch_info->ip.i;
1282 /* Encode type+position compactly */
1283 g_assert (patch_info->type < 64);
1284 if (offset < 1024 - 1) {
1285 fprintf (tmpfp, "\t.byte %d\n", (patch_info->type << 2) + (offset >> 8));
1286 fprintf (tmpfp, "\t.byte %d\n", offset & ((1 << 8) - 1));
1289 fprintf (tmpfp, "\t.byte %d\n", (patch_info->type << 2) + 3);
1290 fprintf (tmpfp, "\t.byte %d\n", 255);
1291 emit_alignment(tmpfp, 4);
1292 fprintf (tmpfp, "\t.long %d\n", offset);
1297 * 0 is PATCH_INFO_BB, which can't be in the file.
1299 /* NULL terminated array */
1300 fprintf (tmpfp, "\t.byte 0\n");
1302 emit_alignment (tmpfp, sizeof (gpointer));
1304 /* Then emit the other info */
1305 for (pindex = 0; pindex < patches->len; ++pindex) {
1306 patch_info = g_ptr_array_index (patches, pindex);
1308 if ((patch_info->type == MONO_PATCH_INFO_LABEL) ||
1309 (patch_info->type == MONO_PATCH_INFO_BB))
1313 switch (patch_info->type) {
1314 case MONO_PATCH_INFO_METHODCONST:
1315 case MONO_PATCH_INFO_METHOD:
1316 case MONO_PATCH_INFO_METHOD_JUMP:
1317 case MONO_PATCH_INFO_CLASS:
1318 case MONO_PATCH_INFO_IID:
1319 case MONO_PATCH_INFO_FIELD:
1320 case MONO_PATCH_INFO_INTERNAL_METHOD:
1321 case MONO_PATCH_INFO_IMAGE:
1322 case MONO_PATCH_INFO_VTABLE:
1323 case MONO_PATCH_INFO_CLASS_INIT:
1324 case MONO_PATCH_INFO_SFLDA:
1325 case MONO_PATCH_INFO_EXC_NAME:
1326 emit_pointer (tmpfp, patch_info->data.name);
1329 case MONO_PATCH_INFO_SWITCH:
1330 case MONO_PATCH_INFO_R4:
1331 case MONO_PATCH_INFO_R8:
1332 case MONO_PATCH_INFO_METHOD_REL:
1333 case MONO_PATCH_INFO_LDSTR:
1334 case MONO_PATCH_INFO_LDTOKEN:
1335 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1336 case MONO_PATCH_INFO_WRAPPER: {
1338 sprintf (buf, "%s_p_%d", mname, j);
1339 emit_pointer (tmpfp, buf);
1343 case MONO_PATCH_INFO_LABEL:
1344 case MONO_PATCH_INFO_BB:
1347 g_warning ("unable to handle jump info %d", patch_info->type);
1348 g_assert_not_reached ();
1358 mono_debug_serialize_debug_info (cfg, &buf, &buf_len);
1360 fprintf (tmpfp, "\t.long %d\n", buf_len);
1362 for (i = 0; i < buf_len; ++i)
1363 fprintf (tmpfp, ".byte %d\n", (unsigned int) buf [i]);
1369 /* fixme: save the rest of the required infos */
1376 str_begins_with (const char *str1, const char *str2)
1378 int len = strlen (str2);
1379 return strncmp (str1, str2, len) == 0;
1383 mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts)
1385 gchar **args, **ptr;
1387 memset (opts, 0, sizeof (*opts));
1389 args = g_strsplit (aot_options ? aot_options : "", ",", -1);
1390 for (ptr = args; ptr && *ptr; ptr ++) {
1391 const char *arg = *ptr;
1393 if (str_begins_with (arg, "outfile=")) {
1394 opts->outfile = g_strdup (arg + strlen ("outfile="));
1397 fprintf (stderr, "AOT : Unknown argument '%s'.\n", arg);
1404 mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
1407 MonoImage *image = ass->image;
1409 char *com, *tmpfname, *opts_str;
1413 int ccount = 0, mcount = 0, lmfcount = 0, abscount = 0, wrappercount = 0, ocount = 0;
1414 GHashTable *ref_hash;
1415 MonoAotCompile *acfg;
1417 MonoAotOptions aot_opts;
1418 char *outfile_name, *tmp_outfile_name;
1420 printf ("Mono Ahead of Time compiler - compiling assembly %s\n", image->name);
1422 mono_aot_parse_options (aot_options, &aot_opts);
1424 i = g_file_open_tmp ("mono_aot_XXXXXX", &tmpfname, NULL);
1425 tmpfp = fdopen (i, "w+");
1428 ref_hash = g_hash_table_new (NULL, NULL);
1430 acfg = g_new0 (MonoAotCompile, 1);
1432 acfg->ref_hash = ref_hash;
1433 acfg->icall_hash = g_hash_table_new (NULL, NULL);
1434 acfg->icall_table = g_ptr_array_new ();
1435 acfg->image_hash = g_hash_table_new (NULL, NULL);
1436 acfg->image_table = g_ptr_array_new ();
1438 write_string_symbol (tmpfp, "mono_assembly_guid" , image->guid);
1440 write_string_symbol (tmpfp, "mono_aot_version", MONO_AOT_FILE_VERSION);
1442 opts_str = g_strdup_printf ("%d", opts);
1443 write_string_symbol (tmpfp, "mono_aot_opt_flags", opts_str);
1446 emitted = g_new0 (gboolean, image->tables [MONO_TABLE_METHOD].rows);
1448 for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
1449 MonoJumpInfo *patch_info;
1451 guint32 token = MONO_TOKEN_METHOD_DEF | (i + 1);
1452 method = mono_get_method (image, token, NULL);
1454 /* fixme: maybe we can also precompile wrapper methods */
1455 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
1456 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
1457 (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
1458 (method->flags & METHOD_ATTRIBUTE_ABSTRACT)) {
1459 //printf ("Skip (impossible): %s\n", mono_method_full_name (method, TRUE));
1465 /* fixme: we need to patch the IP for the LMF in that case */
1466 if (method->save_lmf) {
1467 //printf ("Skip (needs lmf): %s\n", mono_method_full_name (method, TRUE));
1472 //printf ("START: %s\n", mono_method_full_name (method, TRUE));
1473 //mono_compile_method (method);
1475 cfg = mini_method_compile (method, opts, mono_get_root_domain (), FALSE, 0);
1478 if (cfg->disable_aot) {
1479 printf ("Skip (other): %s\n", mono_method_full_name (method, TRUE));
1485 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
1486 if (patch_info->type == MONO_PATCH_INFO_ABS) {
1487 /* unable to handle this */
1488 //printf ("Skip (abs addr): %s %d\n", mono_method_full_name (method, TRUE), patch_info->type);
1499 /* some wrappers are very common */
1500 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
1501 if (patch_info->type == MONO_PATCH_INFO_METHODCONST) {
1502 switch (patch_info->data.method->wrapper_type) {
1503 case MONO_WRAPPER_PROXY_ISINST:
1504 patch_info->type = MONO_PATCH_INFO_WRAPPER;
1508 if (patch_info->type == MONO_PATCH_INFO_METHOD) {
1509 switch (patch_info->data.method->wrapper_type) {
1510 case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK:
1511 case MONO_WRAPPER_STFLD:
1512 case MONO_WRAPPER_LDFLD:
1513 patch_info->type = MONO_PATCH_INFO_WRAPPER;
1520 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
1521 if ((patch_info->type == MONO_PATCH_INFO_METHOD ||
1522 patch_info->type == MONO_PATCH_INFO_METHODCONST) &&
1523 patch_info->data.method->wrapper_type) {
1524 /* unable to handle this */
1525 //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));
1536 //printf ("Compile: %s\n", mono_method_full_name (method, TRUE));
1539 emit_method (acfg, cfg);
1541 mono_destroy_compile (cfg);
1547 * The icall and image tables are small but referenced in a lot of places.
1548 * So we emit them at once, and reference their elements by an index
1549 * instead of an assembly label to cut back on the number of relocations.
1552 /* Emit icall table */
1554 symbol = g_strdup_printf ("mono_icall_table");
1555 emit_section_change (tmpfp, ".text", 1);
1556 emit_global(tmpfp, symbol);
1557 emit_alignment(tmpfp, 8);
1558 emit_label(tmpfp, symbol);
1559 fprintf (tmpfp, ".long %d\n", acfg->icall_table->len);
1560 for (i = 0; i < acfg->icall_table->len; i++)
1561 fprintf (tmpfp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, (char*)g_ptr_array_index (acfg->icall_table, i));
1563 /* Emit image table */
1565 symbol = g_strdup_printf ("mono_image_table");
1566 emit_section_change (tmpfp, ".text", 1);
1567 emit_global(tmpfp, symbol);
1568 emit_alignment(tmpfp, 8);
1569 emit_label(tmpfp, symbol);
1570 fprintf (tmpfp, ".long %d\n", acfg->image_table->len);
1571 for (i = 0; i < acfg->image_table->len; i++)
1572 fprintf (tmpfp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, ((MonoImage*)g_ptr_array_index (acfg->image_table, i))->guid);
1575 * g_module_symbol takes a lot of time for failed lookups, so we emit
1576 * a table which contains one bit for each method. This bit specifies
1577 * whenever the method is emitted or not.
1580 symbol = g_strdup_printf ("mono_methods_present_table");
1581 emit_section_change (tmpfp, ".text", 1);
1582 emit_global(tmpfp, symbol);
1583 emit_alignment(tmpfp, 8);
1584 emit_label(tmpfp, symbol);
1589 nrows = image->tables [MONO_TABLE_METHOD].rows;
1590 for (i = 0; i < nrows / 32 + 1; ++i) {
1592 for (k = 0; k < 32; ++k) {
1593 if (emitted [(i * 32) + k])
1596 //printf ("EMITTED [%d] = %d.\n", i, b);
1597 fprintf (tmpfp, "\t.long %d\n", w);
1603 #if defined(sparc) && SIZEOF_VOID_P == 8
1604 com = g_strdup_printf ("as -xarch=v9 %s -o %s.o", tmpfname, tmpfname);
1606 com = g_strdup_printf ("as %s -o %s.o", tmpfname, tmpfname);
1608 printf ("Executing the native assembler: %s\n", com);
1609 if (system (com) != 0) {
1616 if (aot_opts.outfile)
1617 outfile_name = g_strdup_printf ("%s", aot_opts.outfile);
1619 outfile_name = g_strdup_printf ("%s%s", image->name, SHARED_EXT);
1621 tmp_outfile_name = g_strdup_printf ("%s.tmp", outfile_name);
1624 com = g_strdup_printf ("ld -shared -G -o %s %s.o", outfile_name, tmpfname);
1625 #elif defined(__ppc__) && defined(__MACH__)
1626 com = g_strdup_printf ("gcc -dynamiclib -o %s %s.o", outfile_name, tmpfname);
1628 com = g_strdup_printf ("ld -shared -o %s %s.o", outfile_name, tmpfname);
1630 printf ("Executing the native linker: %s\n", com);
1631 if (system (com) != 0) {
1632 g_free (tmp_outfile_name);
1633 g_free (outfile_name);
1639 com = g_strdup_printf ("%s.o", tmpfname);
1642 /*com = g_strdup_printf ("strip --strip-unneeded %s%s", image->name, SHARED_EXT);
1643 printf ("Stripping the binary: %s\n", com);
1647 rename (tmp_outfile_name, outfile_name);
1649 g_free (tmp_outfile_name);
1650 g_free (outfile_name);
1652 printf ("Compiled %d out of %d methods (%d%%)\n", ccount, mcount, mcount ? (ccount*100)/mcount : 100);
1653 printf ("%d methods contain absolute addresses (%d%%)\n", abscount, mcount ? (abscount*100)/mcount : 100);
1654 printf ("%d methods contain wrapper references (%d%%)\n", wrappercount, mcount ? (wrappercount*100)/mcount : 100);
1655 printf ("%d methods contain lmf pointers (%d%%)\n", lmfcount, mcount ? (lmfcount*100)/mcount : 100);
1656 printf ("%d methods have other problems (%d%%)\n", ocount, mcount ? (ocount*100)/mcount : 100);
1657 //printf ("Retained input file.\n");