2004-07-02 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mono / mini / aot.c
index 5f4e92cf6489f624e8396113643233e35ce1c09e..d367904f81e5396341f120338ee8f72dc24053de 100644 (file)
 #include <mono/metadata/appdomain.h>
 #include <mono/metadata/debug-helpers.h>
 #include <mono/metadata/assembly.h>
+#include <mono/metadata/metadata-internals.h>
+#include <mono/metadata/marshal.h>
+#include <mono/utils/mono-logger.h>
 #include <mono/os/gc_wrapper.h>
 
 #include "mini.h"
 
 #ifdef PLATFORM_WIN32
 #define SHARED_EXT ".dll"
+#elif defined(__ppc__) && defined(__MACH__)
+#define SHARED_EXT ".dylib"
 #else
 #define SHARED_EXT ".so"
 #endif
 
+#if defined(sparc) || defined(__ppc__)
+#define AS_STRING_DIRECTIVE ".asciz"
+#else
+/* GNU as */
+#define AS_STRING_DIRECTIVE ".string"
+#endif
+
+#define ALIGN_PTR_TO(ptr,align) (gpointer)((((gssize)(ptr)) + (align - 1)) & (~(align - 1)))
+
 typedef struct MonoAotMethod {
        MonoJitInfo *info;
        MonoJumpInfo *patch_info;
+       MonoDomain *domain;
 } MonoAotMethod;
 
 typedef struct MonoAotModule {
@@ -68,22 +83,36 @@ static MonoGHashTable *aot_modules;
 
 static CRITICAL_SECTION aot_mutex;
 
-static guint32 mono_aot_verbose = 0;
+/*
+ * Disabling this will make a copy of the loaded code and use the copy instead 
+ * of the original. This will place the caller and the callee close to each 
+ * other in memory, possibly improving cache behavior. Since the original
+ * code is in copy-on-write memory, this will not increase the memory usage
+ * of the runtime.
+ */
+static gboolean use_loaded_code = FALSE;
+
+/* For debugging */
+static gint32 mono_last_aot_method = -1;
+
+static MonoJitInfo*
+mono_aot_load_method (MonoDomain *domain, MonoAotModule *aot_module, MonoMethod *method, guint8 *code, guint8 *info);
 
 static MonoClass * 
-decode_class_info (MonoAotModule *module, gpointer *data)
+decode_class_info (MonoAotModule *module, guint32 *data)
 {
        MonoImage *image;
        MonoClass *klass;
        
-       image = module->image_table [(guint32)data [1]];
+       image = module->image_table [data [1]];
        g_assert (image);
 
        if (data [0]) {
-               return mono_class_get (image, (guint32)data [0]);
+               return mono_class_get (image, data [0]);
        } else {
-               klass = decode_class_info (module, data [3]);
-               return mono_array_class_get (klass, (guint32)data [2]);
+               /* the pointer is dword aligned */
+               klass = decode_class_info (module, *(guint32**)(ALIGN_PTR_TO (&data[3], sizeof (gpointer))));
+               return mono_array_class_get (klass, data [2]);
        }
 
        return NULL;
@@ -99,29 +128,27 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data)
        char *aot_version = NULL;
        char *opt_flags = NULL;
 
-       if (mono_no_aot)
-               return;
-
-       aot_name = g_strdup_printf ("%s.so", assembly->image->name);
+       aot_name = g_strdup_printf ("%s%s", assembly->image->name, SHARED_EXT);
 
        assembly->aot_module = g_module_open (aot_name, G_MODULE_BIND_LAZY);
 
-       if (!assembly->aot_module)
+       if (!assembly->aot_module) {
+               mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT Failed to load AOT module %s: %s\n", aot_name, g_module_error ());
+               g_free (aot_name);
                return;
+       }
 
        g_module_symbol (assembly->aot_module, "mono_assembly_guid", (gpointer *) &saved_guid);
        g_module_symbol (assembly->aot_module, "mono_aot_version", (gpointer *) &aot_version);
        g_module_symbol (assembly->aot_module, "mono_aot_opt_flags", (gpointer *)&opt_flags);
 
        if (!aot_version || strcmp (aot_version, MONO_AOT_FILE_VERSION)) {
-               if (mono_aot_verbose > 0)
-                       printf ("AOT module %s has wrong file format version (expected %s got %s)\n", aot_name, MONO_AOT_FILE_VERSION, aot_version);
+               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);
                usable = FALSE;
        }
        else
                if (!saved_guid || strcmp (assembly->image->guid, saved_guid)) {
-                       if (mono_aot_verbose > 0)
-                               printf ("AOT module %s is out of date.\n", aot_name);
+                       mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT Module %s is out of date.\n", aot_name);
                        usable = FALSE;
                }
 
@@ -158,11 +185,12 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data)
                for (i = 0; i < table_len; ++i) {
                        info->image_table [i] = mono_image_loaded_by_guid (table);
                        if (!info->image_table [i]) {
-                               if (mono_aot_verbose > 0)
-                                       printf ("AOT module %s is out of date.\n", aot_name);
-                               g_free (info->methods);
+                               mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT module %s is out of date.\n", aot_name);
+                               mono_g_hash_table_destroy (info->methods);
                                g_free (info->image_table);
+#ifndef HAVE_BOEHM_GC
                                g_free (info);
+#endif
                                g_free (aot_name);
                                g_module_close (assembly->aot_module);
                                assembly->aot_module = NULL;
@@ -197,8 +225,7 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data)
        mono_g_hash_table_insert (aot_modules, assembly, info);
        LeaveCriticalSection (&aot_mutex);
 
-       if (mono_aot_verbose > 0)
-               printf ("Loaded AOT Module for %s.\n", assembly->image->name);
+       mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT Loaded AOT Module for %s.\n", assembly->image->name);
 }
 
 void
@@ -209,6 +236,9 @@ mono_aot_init (void)
        aot_modules = mono_g_hash_table_new (NULL, NULL);
 
        mono_install_assembly_load_hook (load_aot_module, NULL);
+
+       if (getenv ("MONO_LASTAOT"))
+               mono_last_aot_method = atoi (getenv ("MONO_LASTAOT"));
 }
  
 static MonoJitInfo *
@@ -216,13 +246,11 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method)
 {
        MonoClass *klass = method->klass;
        MonoAssembly *ass = klass->image->assembly;
-       MonoJumpInfo *patch_info = NULL;
        GModule *module = ass->aot_module;
        char method_label [256];
        char info_label [256];
        guint8 *code = NULL;
-       gpointer *info;
-       guint code_len, used_int_regs, used_strings;
+       guint8 *info;
        MonoAotModule *aot_module;
        MonoAotMethod *minfo;
        MonoJitInfo *jinfo;
@@ -235,6 +263,9 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method)
        if (!method->token)
                return NULL;
 
+       if (mono_profiler_get_events () & MONO_PROFILE_ENTER_LEAVE)
+               return NULL;
+
        if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
                (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
                (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
@@ -246,7 +277,10 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method)
        g_assert (klass->inited);
 
        minfo = mono_g_hash_table_lookup (aot_module->methods, method);
-       if (minfo) {
+       /* Can't use code from non-root domains since they can be unloaded */
+       if (minfo && (minfo->domain == mono_get_root_domain ())) {
+               /* This method was already loaded in another appdomain */
+
                /* Duplicate jinfo */
                jinfo = mono_mempool_alloc0 (domain->mp, sizeof (MonoJitInfo));
                memcpy (jinfo, minfo->info, sizeof (MonoJitInfo));
@@ -256,7 +290,6 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method)
                        memcpy (jinfo->clauses, minfo->info->clauses, sizeof (MonoJitExceptionInfo) * header->num_clauses);
                }
 
-               /* This method was already loaded in another appdomain */
                if (aot_module->opts & MONO_OPT_SHARED)
                        /* Use the same method in the new appdomain */
                        ;
@@ -266,16 +299,16 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method)
                else {
                        /* Create a copy of the original method and apply relocations */
 
-                       code = mono_mempool_alloc (domain->code_mp, minfo->info->code_size);
+                       code = mono_code_manager_reserve (domain->code_mp, minfo->info->code_size);
                        memcpy (code, minfo->info->code_start, minfo->info->code_size);
 
-                       if (mono_aot_verbose > 1)
-                               printf ("REUSE METHOD: %s %p - %p.\n", mono_method_full_name (method, TRUE), code, (char*)code + code_len);
+                       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);
 
                        /* Do this outside the lock to avoid deadlocks */
                        LeaveCriticalSection (&aot_mutex);
-                       mono_arch_patch_code (method, domain, code, minfo->patch_info);
+                       mono_arch_patch_code (method, domain, code, minfo->patch_info, TRUE);
                        EnterCriticalSection (&aot_mutex);
+                       mono_arch_flush_icache (code, minfo->info->code_size);
 
                        /* Relocate jinfo */
                        jinfo->code_start = code;
@@ -302,8 +335,7 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method)
                guint32 w;
                w = aot_module->methods_present_table [index / 32];
                if (! (w & (1 << (index % 32)))) {
-                       if (mono_aot_verbose > 1)
-                               printf ("NOT FOUND: %s.\n", mono_method_full_name (method, TRUE));
+                       mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT NOT FOUND: %s.\n", mono_method_full_name (method, TRUE));
                        return NULL;
                }
        }
@@ -318,36 +350,52 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method)
        if (!g_module_symbol (module, info_label, (gpointer *)&info))
                return NULL;
 
-       {
-               static int count = 0;
-
-               count ++;
-
-               if (getenv ("MONO_LASTAOT")) {
-                       if (count > atoi(getenv ("MONO_LASTAOT"))) {
+       if (mono_last_aot_method != -1) {
+               if (mono_jit_stats.methods_aot > mono_last_aot_method)
                                return NULL;
-                       }
-                       else
-                               if (count == atoi(getenv ("MONO_LASTAOT")))
-                                       printf ("LAST AOT METHOD: %s.%s.%s.\n", klass->name_space, klass->name, method->name);
-               }
+               else
+                       if (mono_jit_stats.methods_aot == mono_last_aot_method)
+                               printf ("LAST AOT METHOD: %s.%s.%s.\n", klass->name_space, klass->name, method->name);
        }
 
+       return mono_aot_load_method (domain, aot_module, method, code, info);
+}
+
+static MonoJitInfo*
+mono_aot_load_method (MonoDomain *domain, MonoAotModule *aot_module, MonoMethod *method, guint8 *code, guint8 *info)
+{
+       MonoClass *klass = method->klass;
+       MonoJumpInfo *patch_info = NULL;
+       guint code_len, used_int_regs, used_strings;
+       MonoAotMethod *minfo;
+       MonoJitInfo *jinfo;
+       MonoMethodHeader *header = ((MonoMethodNormal*)method)->header;
+       GPtrArray *patches;
+       int i, pindex;
+
 #ifdef HAVE_BOEHM_GC
        minfo = GC_MALLOC (sizeof (MonoAotMethod));
 #else
        minfo = g_new0 (MonoAotMethod, 1);
 #endif
 
+       minfo->domain = domain;
        jinfo = mono_mempool_alloc0 (domain->mp, sizeof (MonoJitInfo));
 
-       code_len = GPOINTER_TO_UINT (*((gpointer **)info));
-       info++;
-       used_int_regs = GPOINTER_TO_UINT (*((gpointer **)info));
-       info++;
+       code_len = *(guint32*)info;
+       info += 4;
+       used_int_regs = *(guint32*)info;
+       info += 4;
+
+       if (!use_loaded_code) {
+               guint8 *code2;
+               code2 = mono_code_manager_reserve (domain->code_mp, code_len);
+               memcpy (code2, code, code_len);
+               mono_arch_flush_icache (code2, code_len);
+               code = code2;
+       }
 
-       if (mono_aot_verbose > 1)
-               printf ("FOUND AOT compiled code for %s %p - %p %p\n", mono_method_full_name (method, TRUE), code, code + code_len, info);
+       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);
 
        /* Exception table */
        if (header->num_clauses) {
@@ -355,8 +403,8 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method)
                        mono_mempool_alloc0 (domain->mp, sizeof (MonoJitExceptionInfo) * header->num_clauses);
                jinfo->num_clauses = header->num_clauses;
 
-               jinfo->exvar_offset = GPOINTER_TO_UINT (*((gpointer**)info));
-               info ++;
+               jinfo->exvar_offset = *(guint32*)info;
+               info += 4;
 
                for (i = 0; i < header->num_clauses; ++i) {
                        MonoExceptionClause *ec = &header->clauses [i];                         
@@ -364,30 +412,30 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method)
 
                        ei->flags = ec->flags;
                        if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)
-                               ei->data.filter = code + GPOINTER_TO_UINT (*((gpointer**)info));
+                               ei->data.filter = code + *(guint32*)info;
                        else
-                               ei->data.token = GPOINTER_TO_UINT (*((gpointer**)info));
-                       info ++;
-                       ei->try_start = code + GPOINTER_TO_UINT (*((gpointer**)info));
-                       info ++;
-                       ei->try_end = code + GPOINTER_TO_UINT (*((gpointer**)info));
-                       info ++;
-                       ei->handler_start = code + GPOINTER_TO_UINT (*((gpointer**)info));
-                       info ++;
+                               ei->data.token = *(guint32*)info;
+                       info += 4;
+                       ei->try_start = code + *(guint32*)info;
+                       info += 4;
+                       ei->try_end = code + *(guint32*)info;
+                       info += 4;
+                       ei->handler_start = code + *(guint32*)info;
+                       info += 4;
                }
        }
 
        if (aot_module->opts & MONO_OPT_SHARED) {
-               used_strings = GPOINTER_TO_UINT (*((gpointer **)info));
-               info++;
+               used_strings = *(guint32*)info;
+               info += 4;
        }
        else
                used_strings = 0;
 
        for (i = 0; i < used_strings; i++) {
-               guint token =  GPOINTER_TO_UINT (*((gpointer **)info));
-               info++;
-               mono_ldstr (mono_root_domain, klass->image, mono_metadata_token_index (token));
+               guint token =  *(guint32*)info;
+               info += 4;
+               mono_ldstr (mono_get_root_domain (), klass->image, mono_metadata_token_index (token));
        }
 
        if (*info) {
@@ -397,28 +445,33 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method)
                gpointer *table;
                int pages;
                int i, err;
-               guint32 last_offset;
+               guint32 last_offset, buf_len;
+               guint32 *data;
 
                if (aot_module->opts & MONO_OPT_SHARED)
                        mp = mono_mempool_new ();
                else
                        mp = domain->mp;
 
+               /* First load the type + offset table */
                last_offset = 0;
+               patches = g_ptr_array_new ();
                while (*info) {
                        MonoJumpInfo *ji = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
+
                        guint8 b1, b2;
 
                        b1 = *(guint8*)info;
                        b2 = *((guint8*)info + 1);
-
-                       info = (gpointer*)((guint8*)info + 2);
+                       
+                       info += 2;
 
                        ji->type = b1 >> 2;
 
                        if (((b1 & (1 + 2)) == 3) && (b2 == 255)) {
-                               ji->ip.i = GPOINTER_TO_UINT (*info);
-                               info ++;
+                               info = ALIGN_PTR_TO (info, 4);
+                               ji->ip.i = *(guint32*)info;
+                               info += 4;
                        }
                        else
                                ji->ip.i = (((guint32)(b1 & (1 + 2))) << 8) + b2;
@@ -427,7 +480,21 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method)
                        last_offset = ji->ip.i;
                        //printf ("T: %d O: %d.\n", ji->type, ji->ip.i);
 
-                       gpointer *data = *((gpointer **)info);
+                       ji->next = patch_info;
+                       patch_info = ji;
+
+                       g_ptr_array_add (patches, ji);
+               }
+               info ++;
+
+               info = ALIGN_PTR_TO (info, sizeof (gpointer));
+
+               /* Then load the other data */
+               for (pindex = 0; pindex < patches->len; ++pindex) {
+                       MonoJumpInfo *ji = g_ptr_array_index (patches, pindex);
+               
+                       data = *((guint32 **)info);
+                       info += sizeof (gpointer);
 
                        switch (ji->type) {
                        case MONO_PATCH_INFO_CLASS:
@@ -437,6 +504,7 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method)
                                mono_class_init (ji->data.klass);
                                break;
                        case MONO_PATCH_INFO_VTABLE:
+                       case MONO_PATCH_INFO_CLASS_INIT:
                                ji->data.klass = decode_class_info (aot_module, data);
                                g_assert (ji->data.klass);
                                mono_class_init (ji->data.klass);
@@ -446,7 +514,8 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method)
                                g_assert (ji->data.image);
                                break;
                        case MONO_PATCH_INFO_METHOD:
-                       case MONO_PATCH_INFO_METHODCONST: {
+                       case MONO_PATCH_INFO_METHODCONST:
+                       case MONO_PATCH_INFO_METHOD_JUMP: {
                                guint32 image_index, token;
 
                                image_index = (guint32)data >> 24;
@@ -459,11 +528,31 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method)
 
                                break;
                        }
+                       case MONO_PATCH_INFO_WRAPPER: {
+                               guint32 image_index, token;
+                               guint32 wrapper_type;
+
+                               wrapper_type = (guint32)data[0];
+                               image_index = (guint32)data[1] >> 24;
+                               token = MONO_TOKEN_METHOD_DEF | ((guint32)data[1] & 0xffffff);
+
+                               image = aot_module->image_table [image_index];
+                               ji->data.method = mono_get_method (image, token, NULL);
+                               g_assert (ji->data.method);
+                               mono_class_init (ji->data.method->klass);
+
+                               g_assert (wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK);
+                               ji->type = MONO_PATCH_INFO_METHOD;
+                               ji->data.method = mono_marshal_get_remoting_invoke_with_check (ji->data.method);
+                               break;
+                       }
                        case MONO_PATCH_INFO_FIELD:
                        case MONO_PATCH_INFO_SFLDA: {
-                               MonoClass *klass = decode_class_info (aot_module, data [1]);
+                               /* The pointer is dword aligned */
+                               gpointer class_ptr = *(gpointer*)(ALIGN_PTR_TO (&data[1], sizeof (gpointer)));
+                               MonoClass *klass = decode_class_info (aot_module, class_ptr);
                                mono_class_init (klass);
-                               ji->data.field = mono_class_get_field (klass, (guint32)data [0]);
+                               ji->data.field = mono_class_get_field (klass, data [0]);
                                break;
                        }
                        case MONO_PATCH_INFO_INTERNAL_METHOD:
@@ -472,7 +561,7 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method)
                                //printf ("A: %s.\n", ji->data.name);
                                break;
                        case MONO_PATCH_INFO_SWITCH:
-                               ji->table_size = (int)data [0];
+                               ji->table_size = data [0];
                                table = g_new (gpointer, ji->table_size);
                                ji->data.target = table;
                                for (i = 0; i < ji->table_size; i++) {
@@ -486,7 +575,8 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method)
                        case MONO_PATCH_INFO_LDSTR:
                        case MONO_PATCH_INFO_LDTOKEN:
                        case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
-                               ji->data.target = *data;
+                               image = aot_module->image_table [data [0]];
+                               ji->data.token = mono_jump_info_token_new (mp, image, data [1]);
                                break;
                        case MONO_PATCH_INFO_EXC_NAME:
                                ji->data.klass = decode_class_info (aot_module, data);
@@ -495,34 +585,39 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method)
                                ji->data.name = ji->data.klass->name;
                                break;
                        case MONO_PATCH_INFO_METHOD_REL:
-                               ji->data.offset = (int)data [0];
+                               ji->data.offset = data [0];
                                break;
                        default:
                                g_warning ("unhandled type %d", ji->type);
                                g_assert_not_reached ();
                        }
-
-                       info++;
-                       ji->next = patch_info;
-                       patch_info = ji;
                }
 
-#ifndef PLATFORM_WIN32
+               g_ptr_array_free (patches, TRUE);
+
+               info += 4;
+               buf_len = *(guint32*)info;
+               info += 4;
+               mono_debug_add_aot_method (domain, method, code, info, buf_len);
+
+               if (use_loaded_code) {
                /* disable write protection */
-               page_start = (char *) (((int) (code)) & ~ (PAGESIZE - 1));
-               pages = (code + code_len - page_start + PAGESIZE - 1) / PAGESIZE;
-               err = mprotect (page_start, pages * PAGESIZE, PROT_READ | PROT_WRITE | PROT_EXEC);
-               g_assert (err == 0);
+#ifndef PLATFORM_WIN32
+                       page_start = (char *) (((int) (code)) & ~ (PAGESIZE - 1));
+                       pages = (code + code_len - page_start + PAGESIZE - 1) / PAGESIZE;
+                       err = mprotect (page_start, pages * PAGESIZE, PROT_READ | PROT_WRITE | PROT_EXEC);
+                       g_assert (err == 0);
 #else
-               {
-                       DWORD oldp;
-                       g_assert (VirtualProtect (code, code_len, PAGE_EXECUTE_READWRITE, &oldp) != 0);
-               }
+                       {
+                               DWORD oldp;
+                               g_assert (VirtualProtect (code, code_len, PAGE_EXECUTE_READWRITE, &oldp) != 0);
+                       }
 #endif
+               }
 
                /* Do this outside the lock to avoid deadlocks */
                LeaveCriticalSection (&aot_mutex);
-               mono_arch_patch_code (method, domain, code, patch_info);
+               mono_arch_patch_code (method, domain, code, patch_info, TRUE);
                EnterCriticalSection (&aot_mutex);
 
                if (aot_module->opts & MONO_OPT_SHARED)
@@ -566,15 +661,53 @@ mono_aot_get_method (MonoDomain *domain, MonoMethod *method)
                return NULL;
 }
 
+static void
+emit_section_change (FILE *fp, const char *section_name, int subsection_index)
+{
+#if defined(sparc)
+       /* For solaris as, GNU as should accept the same */
+       fprintf (fp, ".section \"%s\"\n", section_name);
+#elif defined(__ppc__) && defined(__MACH__)
+       /* This needs to be made more precise on mach. */
+       fprintf (fp, "%s\n", subsection_index == 0 ? ".text" : ".data");
+#else
+       fprintf (fp, "%s %d\n", section_name, subsection_index);
+#endif
+}
+
+static void
+emit_global (FILE *fp, const char *name)
+{
+#if defined(__ppc__) && defined(__MACH__)
+    // mach-o always uses a '_' prefix.
+       fprintf (fp, ".globl _%s\n", name);
+#else
+       fprintf (fp, ".globl %s\n", name);
+#endif
+}
+
+static void
+emit_label (FILE *fp, const char *name)
+{
+#if defined(__ppc__) && defined(__MACH__)
+    // mach-o always uses a '_' prefix.
+       fprintf (fp, "_%s:\n", name);
+#else
+       fprintf (fp, "%s:\n", name);
+#endif
+}
+
 #if 0
 static void
 write_data_symbol (FILE *fp, const char *name, guint8 *buf, int size, int align)
 {
        int i;
 
+       emit_section_change (fp, ".text", 1);
+
        fprintf (fp, ".globl %s\n", name);
-       fprintf (fp, ".text 1 \n\t.align %d\n", align);
-       fprintf (fp, "\t.type %s,@object\n", name);
+       fprintf (fp, "\t.align %d\n", align);
+       fprintf (fp, "\t.type %s,#object\n", name);
        fprintf (fp, "\t.size %s,%d\n", name, size);
        fprintf (fp, "%s:\n", name);
        for (i = 0; i < size; i++) { 
@@ -587,10 +720,10 @@ write_data_symbol (FILE *fp, const char *name, guint8 *buf, int size, int align)
 static void
 write_string_symbol (FILE *fp, const char *name, const char *value)
 {
-       fprintf (fp, ".globl %s\n", name);
-       fprintf (fp, ".text 1\n");
-       fprintf (fp, "%s:\n", name);
-       fprintf (fp, "\t.string \"%s\"\n", value);
+       emit_section_change (fp, ".text", 1);
+       emit_global(fp, name);
+       emit_label(fp, name);
+       fprintf (fp, "\t%s \"%s\"\n", AS_STRING_DIRECTIVE, value);
 }
 
 static guint32
@@ -634,6 +767,40 @@ emit_image_index (MonoAotCompile *cfg, MonoImage *image)
        fprintf (cfg->fp, "\t.long %d\n", image_index);
 }
 
+#if defined(__ppc__) && defined(__MACH__)
+static int
+ilog2(register int value)
+{
+    int count = -1;
+    while (value & ~0xf) count += 4, value >>= 4;
+    while (value) count++, value >>= 1;
+    return count;
+}
+#endif
+
+static void emit_alignment(FILE *fp, int size)
+{
+#if defined(__ppc__) && defined(__MACH__)
+       // the mach-o assembler specifies alignments as powers of 2.
+       fprintf (fp, "\t.align %d\t; ilog2\n", ilog2(size));
+#elif defined(__powerpc__)
+       /* ignore on linux/ppc */
+#else
+       fprintf (fp, "\t.align %d\n", size);
+#endif
+}
+
+static void
+emit_pointer (FILE *fp, const char *target)
+{
+       emit_alignment (fp, sizeof (gpointer));
+#if defined(sparc) && SIZEOF_VOID_P == 8
+       fprintf (fp, "\t.xword %s\n", target);
+#else
+       fprintf (fp, "\t.long %s\n", target);
+#endif
+}
+
 static char *
 cond_emit_klass_label (MonoAotCompile *cfg, MonoClass *klass)
 {
@@ -647,7 +814,8 @@ cond_emit_klass_label (MonoAotCompile *cfg, MonoClass *klass)
                el = cond_emit_klass_label (cfg, klass->element_class);
        }
        
-       fprintf (cfg->fp, "\t.align %d\n", sizeof (gpointer));
+       emit_alignment(cfg->fp, sizeof (gpointer));
+
        l1 = g_strdup_printf ("klass_p_%08x_%p", klass->type_token, klass);
        fprintf (cfg->fp, "%s:\n", l1);
        fprintf (cfg->fp, "\t.long 0x%08x\n", klass->type_token);
@@ -655,7 +823,7 @@ cond_emit_klass_label (MonoAotCompile *cfg, MonoClass *klass)
 
        if (el) {
                fprintf (cfg->fp, "\t.long %d\n", klass->rank); 
-               fprintf (cfg->fp, "\t.long %s\n", el);
+               emit_pointer (cfg->fp, el);
        }
 
        g_hash_table_insert (cfg->ref_hash, klass, l1);
@@ -674,13 +842,13 @@ cond_emit_field_label (MonoAotCompile *cfg, MonoJumpInfo *patch_info)
                return l1;
 
        l2 = cond_emit_klass_label (cfg, field->parent);
-       fprintf (cfg->fp, "\t.align %d\n", sizeof (gpointer));
+       emit_alignment(cfg->fp, sizeof (gpointer));
        token = mono_get_field_token (field);
        g_assert (token);
        l1 = g_strdup_printf ("klass_p_%08x_%p", token, field);
        fprintf (cfg->fp, "%s:\n", l1);
        fprintf (cfg->fp, "\t.long 0x%08x\n", token);
-       fprintf (cfg->fp, "\t.long %s\n", l2);
+       emit_pointer (cfg->fp, l2);
                
        g_hash_table_insert (cfg->ref_hash, field, l1);
 
@@ -711,7 +879,7 @@ emit_method (MonoAotCompile *acfg, MonoCompile *cfg)
        GList *l;
        FILE *tmpfp;
        int i, j, k, pindex;
-       guint8 *code, *mname;
+       guint8 *code, *mname, *mname_p;
        int func_alignment = 16;
        GPtrArray *patches;
        MonoJumpInfo *patch_info;
@@ -722,17 +890,22 @@ emit_method (MonoAotCompile *acfg, MonoCompile *cfg)
        code = cfg->native_code;
        header = ((MonoMethodNormal*)method)->header;
 
-       fprintf (tmpfp, ".text 0\n");
+       emit_section_change (tmpfp, ".text", 0);
        mname = g_strdup_printf ("m_%x", mono_metadata_token_index (method->token));
-       fprintf (tmpfp, "\t.align %d\n", func_alignment);
-       fprintf (tmpfp, ".globl %s\n", mname);
+       mname_p = g_strdup_printf ("%s_p", mname);
+       emit_alignment(tmpfp, func_alignment);
+       emit_global(tmpfp, mname);
+#if defined(sparc)
+       fprintf (tmpfp, "\t.type %s,#function\n", mname);
+#elif !(defined(__ppc__) && defined(__MACH__))
        fprintf (tmpfp, "\t.type %s,@function\n", mname);
-       fprintf (tmpfp, "%s:\n", mname);
+#endif
+       emit_label(tmpfp, mname);
 
        for (i = 0; i < cfg->code_len; i++) 
                fprintf (tmpfp, ".byte %d\n", (unsigned int) code [i]);
 
-       fprintf (tmpfp, ".text 1\n");
+       emit_section_change (tmpfp, ".text", 1);
 
        /* Sort relocations */
        patches = g_ptr_array_new ();
@@ -740,6 +913,7 @@ emit_method (MonoAotCompile *acfg, MonoCompile *cfg)
                g_ptr_array_add (patches, patch_info);
        g_ptr_array_sort (patches, compare_patches);
 
+       /* Emit out of line info for relocations */
        j = 0;
        for (pindex = 0; pindex < patches->len; ++pindex) {
                patch_info = g_ptr_array_index (patches, pindex);
@@ -752,7 +926,7 @@ emit_method (MonoAotCompile *acfg, MonoCompile *cfg)
                        gpointer *table = (gpointer *)patch_info->data.target;
                        int k;
 
-                       fprintf (tmpfp, "\t.align %d\n", sizeof (gpointer));
+                       emit_alignment(tmpfp, sizeof (gpointer));
                        fprintf (tmpfp, "%s_p_%d:\n", mname, j);
                        fprintf (tmpfp, "\t.long %d\n", patch_info->table_size);
                        
@@ -777,7 +951,8 @@ emit_method (MonoAotCompile *acfg, MonoCompile *cfg)
                        break;
                }
                case MONO_PATCH_INFO_METHODCONST:
-               case MONO_PATCH_INFO_METHOD: {
+               case MONO_PATCH_INFO_METHOD:
+               case MONO_PATCH_INFO_METHOD_JUMP: {
                        /*
                         * The majority of patches are for methods, so we emit
                         * them inline instead of defining a label for them to
@@ -793,6 +968,24 @@ emit_method (MonoAotCompile *acfg, MonoCompile *cfg)
                        j++;
                        break;
                }
+               case MONO_PATCH_INFO_WRAPPER: {
+                       MonoMethod *m;
+                       guint32 image_index;
+                       guint32 token;
+
+                       m = mono_marshal_method_from_wrapper (patch_info->data.method);
+                       image_index = get_image_index (acfg, m->klass->image);
+                       token = m->token;
+                       g_assert (image_index < 256);
+                       g_assert (mono_metadata_token_table (token) == MONO_TABLE_METHOD);
+
+                       emit_alignment(tmpfp, sizeof (gpointer));
+                       fprintf (tmpfp, "%s_p_%d:\n", mname, j);
+                       fprintf (tmpfp, "\t.long %d\n", patch_info->data.method->wrapper_type);
+                       fprintf (tmpfp, "\t.long %d\n", (image_index << 24) + (mono_metadata_token_index (token)));
+                       j++;
+                       break;
+               }
                case MONO_PATCH_INFO_FIELD:
                        patch_info->data.name = cond_emit_field_label (acfg, patch_info);
                        j++;
@@ -818,25 +1011,26 @@ emit_method (MonoAotCompile *acfg, MonoCompile *cfg)
                        break;
                }
                case MONO_PATCH_INFO_R4:
-                       fprintf (tmpfp, "\t.align 8\n");
+                       emit_alignment(tmpfp, 8);
                        fprintf (tmpfp, "%s_p_%d:\n", mname, j);
                        fprintf (tmpfp, "\t.long 0x%08x\n", *((guint32 *)patch_info->data.target));     
                        j++;
                        break;
                case MONO_PATCH_INFO_R8:
-                       fprintf (tmpfp, "\t.align 8\n");
+                       emit_alignment(tmpfp, 8);
                        fprintf (tmpfp, "%s_p_%d:\n", mname, j);
                        fprintf (tmpfp, "\t.long 0x%08x\n", *((guint32 *)patch_info->data.target));
                        fprintf (tmpfp, "\t.long 0x%08x\n", *((guint32 *)patch_info->data.target + 1));
                        j++;
                        break;
                case MONO_PATCH_INFO_METHOD_REL:
-                       fprintf (tmpfp, "\t.align %d\n", sizeof (gpointer));
+                       emit_alignment(tmpfp, sizeof (gpointer));
                        fprintf (tmpfp, "%s_p_%d:\n", mname, j);
                        fprintf (tmpfp, "\t.long 0x%08x\n", patch_info->data.offset);
                        j++;
                        break;
                case MONO_PATCH_INFO_VTABLE:
+               case MONO_PATCH_INFO_CLASS_INIT:
                        patch_info->data.name = cond_emit_klass_label (acfg, patch_info->data.klass);
                        j++;
                        break;
@@ -847,9 +1041,10 @@ emit_method (MonoAotCompile *acfg, MonoCompile *cfg)
                case MONO_PATCH_INFO_LDSTR:
                case MONO_PATCH_INFO_LDTOKEN:
                case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
-                       fprintf (tmpfp, "\t.align 8\n");
+                       emit_alignment(tmpfp, 8);
                        fprintf (tmpfp, "%s_p_%d:\n", mname, j);
-                       fprintf (tmpfp, "\t.long 0x%08x\n", patch_info->data.token);
+                       fprintf (tmpfp, "\t.long 0x%08x\n", get_image_index (acfg, patch_info->data.token->image));
+                       fprintf (tmpfp, "\t.long 0x%08x\n", patch_info->data.token->token);
                        j++;
                        break;
                default:
@@ -858,12 +1053,12 @@ emit_method (MonoAotCompile *acfg, MonoCompile *cfg)
                }
        }
 
-       fprintf (tmpfp, ".globl %s_p\n", mname);
-       fprintf (tmpfp, "\t.align %d\n", sizeof (gpointer));
-       fprintf (tmpfp, "%s_p:\n", mname);
+       emit_global (tmpfp, mname_p);
+       emit_alignment (tmpfp, sizeof (gpointer));
+       emit_label (tmpfp, mname_p);
 
        fprintf (tmpfp, "\t.long %d\n", cfg->code_len);
-       fprintf (tmpfp, "\t.long %d\n", cfg->used_int_regs);
+       fprintf (tmpfp, "\t.long %ld\n", (long)cfg->used_int_regs);
 
        /* Exception table */
        if (header->num_clauses) {
@@ -904,6 +1099,8 @@ emit_method (MonoAotCompile *acfg, MonoCompile *cfg)
                last_offset = 0;
 
                j = 0;
+
+               /* First emit the type+position table */
                for (pindex = 0; pindex < patches->len; ++pindex) {
                        guint32 offset;
                        patch_info = g_ptr_array_index (patches, pindex);
@@ -926,21 +1123,42 @@ emit_method (MonoAotCompile *acfg, MonoCompile *cfg)
                        else {
                                fprintf (tmpfp, "\t.byte %d\n", (patch_info->type << 2) + 3);
                                fprintf (tmpfp, "\t.byte %d\n", 255);
+                               emit_alignment(tmpfp, 4);
                                fprintf (tmpfp, "\t.long %d\n", offset);
                        }
+               }
+
+               /*
+                * 0 is PATCH_INFO_BB, which can't be in the file.
+                */
+               /* NULL terminated array */
+               fprintf (tmpfp, "\t.byte 0\n");
+
+               emit_alignment (tmpfp, sizeof (gpointer));
+
+               /* Then emit the other info */
+               for (pindex = 0; pindex < patches->len; ++pindex) {
+                       patch_info = g_ptr_array_index (patches, pindex);
+
+                       if ((patch_info->type == MONO_PATCH_INFO_LABEL) ||
+                               (patch_info->type == MONO_PATCH_INFO_BB))
+                               /* Nothing to do */
+                               continue;
 
                        switch (patch_info->type) {
                        case MONO_PATCH_INFO_METHODCONST:
                        case MONO_PATCH_INFO_METHOD:
+                       case MONO_PATCH_INFO_METHOD_JUMP:
                        case MONO_PATCH_INFO_CLASS:
                        case MONO_PATCH_INFO_IID:
                        case MONO_PATCH_INFO_FIELD:
                        case MONO_PATCH_INFO_INTERNAL_METHOD:
                        case MONO_PATCH_INFO_IMAGE:
                        case MONO_PATCH_INFO_VTABLE:
+                       case MONO_PATCH_INFO_CLASS_INIT:
                        case MONO_PATCH_INFO_SFLDA:
                        case MONO_PATCH_INFO_EXC_NAME:
-                               fprintf (tmpfp, "\t.long %s\n", patch_info->data.name);
+                               emit_pointer (tmpfp, patch_info->data.name);
                                j++;
                                break;
                        case MONO_PATCH_INFO_SWITCH:
@@ -950,9 +1168,13 @@ emit_method (MonoAotCompile *acfg, MonoCompile *cfg)
                        case MONO_PATCH_INFO_LDSTR:
                        case MONO_PATCH_INFO_LDTOKEN:
                        case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
-                               fprintf (tmpfp, "\t.long %s_p_%d\n", mname, j);
+                       case MONO_PATCH_INFO_WRAPPER: {
+                               char buf [256];
+                               sprintf (buf, "%s_p_%d", mname, j);
+                               emit_pointer (tmpfp, buf);
                                j++;
                                break;
+                       }
                        case MONO_PATCH_INFO_LABEL:
                        case MONO_PATCH_INFO_BB:
                                break;
@@ -964,15 +1186,25 @@ emit_method (MonoAotCompile *acfg, MonoCompile *cfg)
                }
        }
 
-       /*
-        * 0 is PATCH_INFO_BB, which can't be in the file.
-        */
-       /* NULL terminated array */
-       fprintf (tmpfp, "\t.long 0\n");
+       {
+               guint8 *buf;
+               guint32 buf_len;
+
+               mono_debug_serialize_debug_info (cfg, &buf, &buf_len);
+
+               fprintf (tmpfp, "\t.long %d\n", buf_len);
+
+               for (i = 0; i < buf_len; ++i)
+                       fprintf (tmpfp, ".byte %d\n", (unsigned int) buf [i]);
+
+               if (buf_len > 0)
+                       g_free (buf);
+       }
 
        /* fixme: save the rest of the required infos */
 
        g_free (mname);
+       g_free (mname_p);
 }
 
 int
@@ -990,7 +1222,7 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts)
        MonoAotCompile *acfg;
        gboolean *emitted;
 
-       printf ("Mono AOT compiler - compiling assembly %s\n", image->name);
+       printf ("Mono Ahead of Time compiler - compiling assembly %s\n", image->name);
 
        i = g_file_open_tmp ("mono_aot_XXXXXX", &tmpfname, NULL);
        tmpfp = fdopen (i, "w+");
@@ -1043,7 +1275,7 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts)
                //printf ("START:           %s\n", mono_method_full_name (method, TRUE));
                //mono_compile_method (method);
 
-               cfg = mini_method_compile (method, opts, mono_root_domain, 0);
+               cfg = mini_method_compile (method, opts, mono_get_root_domain (), FALSE, 0);
                g_assert (cfg);
 
                if (cfg->disable_aot) {
@@ -1067,6 +1299,13 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts)
                        continue;
                }
 
+               /* remoting-invoke-with-check wrappers are very common */
+               for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
+                       if ((patch_info->type == MONO_PATCH_INFO_METHOD) &&
+                               ((patch_info->data.method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)))
+                               patch_info->type = MONO_PATCH_INFO_WRAPPER;
+               }
+
                skip = FALSE;
                for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
                        if ((patch_info->type == MONO_PATCH_INFO_METHOD ||
@@ -1103,24 +1342,24 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts)
        /* Emit icall table */
 
        symbol = g_strdup_printf ("mono_icall_table");
-       fprintf (tmpfp, ".globl %s\n", symbol);
-       fprintf (tmpfp, ".text 1 \n");
-       fprintf (tmpfp, "\t.align 8\n");
-       fprintf (tmpfp, "%s:\n", symbol);
+       emit_section_change (tmpfp, ".text", 1);
+       emit_global(tmpfp, symbol);
+       emit_alignment(tmpfp, 8);
+       emit_label(tmpfp, symbol);
        fprintf (tmpfp, ".long %d\n", acfg->icall_table->len);
        for (i = 0; i < acfg->icall_table->len; i++)
-               fprintf (tmpfp, ".string \"%s\"\n", (char*)g_ptr_array_index (acfg->icall_table, i));
+               fprintf (tmpfp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, (char*)g_ptr_array_index (acfg->icall_table, i));
 
        /* Emit image table */
 
        symbol = g_strdup_printf ("mono_image_table");
-       fprintf (tmpfp, ".globl %s\n", symbol);
-       fprintf (tmpfp, ".text 1 \n");
-       fprintf (tmpfp, "\t.align 8\n");
-       fprintf (tmpfp, "%s:\n", symbol);
+       emit_section_change (tmpfp, ".text", 1);
+       emit_global(tmpfp, symbol);
+       emit_alignment(tmpfp, 8);
+       emit_label(tmpfp, symbol);
        fprintf (tmpfp, ".long %d\n", acfg->image_table->len);
        for (i = 0; i < acfg->image_table->len; i++)
-               fprintf (tmpfp, ".string \"%s\"\n", ((MonoImage*)g_ptr_array_index (acfg->image_table, i))->guid);
+               fprintf (tmpfp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, ((MonoImage*)g_ptr_array_index (acfg->image_table, i))->guid);
 
        /*
         * g_module_symbol takes a lot of time for failed lookups, so we emit
@@ -1129,10 +1368,10 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts)
         */
 
        symbol = g_strdup_printf ("mono_methods_present_table");
-       fprintf (tmpfp, ".globl %s\n", symbol);
-       fprintf (tmpfp, ".text 1 \n");
-       fprintf (tmpfp, "\t.align 8\n");
-       fprintf (tmpfp, "%s:\n", symbol);
+       emit_section_change (tmpfp, ".text", 1);
+       emit_global(tmpfp, symbol);
+       emit_alignment(tmpfp, 8);
+       emit_label(tmpfp, symbol);
        {
                guint32 k, nrows;
                guint32 w;
@@ -1151,13 +1390,31 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts)
 
        fclose (tmpfp);
 
+#if defined(sparc) && SIZEOF_VOID_P == 8
+       com = g_strdup_printf ("as -xarch=v9 %s -o %s.o", tmpfname, tmpfname);
+#else
        com = g_strdup_printf ("as %s -o %s.o", tmpfname, tmpfname);
+#endif
        printf ("Executing the native assembler: %s\n", com);
-       system (com);
+       if (system (com) != 0) {
+               g_free (com);
+               return 1;
+       }
+
        g_free (com);
+#if defined(sparc)
+       com = g_strdup_printf ("ld -shared -G -o %s%s %s.o", image->name, SHARED_EXT, tmpfname);
+#elif defined(__ppc__) && defined(__MACH__)
+       com = g_strdup_printf ("gcc -dynamiclib -o %s%s %s.o", image->name, SHARED_EXT, tmpfname);
+#else
        com = g_strdup_printf ("ld -shared -o %s%s %s.o", image->name, SHARED_EXT, tmpfname);
+#endif
        printf ("Executing the native linker: %s\n", com);
-       system (com);
+       if (system (com) != 0) {
+               g_free (com);
+               return 1;
+       }
+
        g_free (com);
        com = g_strdup_printf ("%s.o", tmpfname);
        unlink (com);
@@ -1167,11 +1424,12 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts)
        system (com);
        g_free (com);*/
 
-       printf ("Compiled %d out of %d methods (%d%%)\n", ccount, mcount, (ccount*100)/mcount);
-       printf ("%d methods contain absolute addresses (%d%%)\n", abscount, (abscount*100)/mcount);
-       printf ("%d methods contain wrapper references (%d%%)\n", wrappercount, (wrappercount*100)/mcount);
-       printf ("%d methods contain lmf pointers (%d%%)\n", lmfcount, (lmfcount*100)/mcount);
-       printf ("%d methods have other problems (%d%%)\n", ocount, (ocount*100)/mcount);
+       printf ("Compiled %d out of %d methods (%d%%)\n", ccount, mcount, mcount ? (ccount*100)/mcount : 100);
+       printf ("%d methods contain absolute addresses (%d%%)\n", abscount, mcount ? (abscount*100)/mcount : 100);
+       printf ("%d methods contain wrapper references (%d%%)\n", wrappercount, mcount ? (wrappercount*100)/mcount : 100);
+       printf ("%d methods contain lmf pointers (%d%%)\n", lmfcount, mcount ? (lmfcount*100)/mcount : 100);
+       printf ("%d methods have other problems (%d%%)\n", ocount, mcount ? (ocount*100)/mcount : 100);
+       //printf ("Retained input file.\n");
        unlink (tmpfname);
 
        return 0;