2007-05-10 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / aot-compiler.c
index 6bbba4789fbd48ae3cea8bf4bbaf71cd21b1fae1..a1cab2b50792b84d9f06871e0661ac8b65aff208 100644 (file)
@@ -69,7 +69,7 @@ typedef struct MonoAotOptions {
 } MonoAotOptions;
 
 typedef struct MonoAotStats {
-       int ccount, mcount, lmfcount, abscount, wrappercount, gcount, ocount;
+       int ccount, mcount, lmfcount, abscount, wrappercount, gcount, ocount, genericcount;
        int code_size, info_size, ex_info_size, got_size, class_info_size, got_info_size, got_info_offsets_size;
        int methods_without_got_slots, direct_calls, all_calls;
        int got_slots;
@@ -94,6 +94,7 @@ typedef struct _BinSection BinSection;
 enum {
        EMIT_NONE,
        EMIT_BYTE,
+       EMIT_WORD,
        EMIT_LONG
 };
 
@@ -133,40 +134,45 @@ typedef struct MonoAotCompile {
 #endif
 } MonoAotCompile;
 
-/* Keep in synch with MonoJumpInfoType */
-static const char* patch_types [] = {
-       "bb",
-       "abs",
-       "label",
-       "method",
-       "method_jump",
-       "method_rel",
-       "methodconst",
-       "internal_method",
-       "switch",
-       "exc",
-       "exc_name",
-       "class",
-       "image",
-       "field",
-       "vtable",
-       "class_init",
-       "sflda",
-       "ldstr",
-       "ldtoken",
-       "type_from_handle",
-       "r4",
-       "r8",
-       "ip",
-       "iid",
-       "adjusted_iid",
-       "bb_ovf",
-       "exc_ovf",
-       "wrapper",
-       "got_offset",
-       "declsec",
-       "none"
+#ifdef HAVE_ARRAY_ELEM_INIT
+#define MSGSTRFIELD(line) MSGSTRFIELD1(line)
+#define MSGSTRFIELD1(line) str##line
+static const struct msgstr_t {
+#define PATCH_INFO(a,b) char MSGSTRFIELD(__LINE__) [sizeof (b)];
+#include "patch-info.h"
+#undef PATCH_INFO
+} opstr = {
+#define PATCH_INFO(a,b) b,
+#include "patch-info.h"
+#undef PATCH_INFO
 };
+static const gint16 opidx [] = {
+#define PATCH_INFO(a,b) [MONO_PATCH_INFO_ ## a] = offsetof (struct msgstr_t, MSGSTRFIELD(__LINE__)),
+#include "patch-info.h"
+#undef PATCH_INFO
+};
+
+static const char*
+get_patch_name (int info)
+{
+       return (const char*)&opstr + opidx [info];
+}
+
+#else
+#define PATCH_INFO(a,b) b,
+static const char* const
+patch_types [MONO_PATCH_INFO_NUM + 1] = {
+#include "patch-info.h"
+       NULL
+};
+
+static const char*
+get_patch_name (int info)
+{
+       return patch_types [info];
+}
+
+#endif
 
 static gboolean 
 is_got_patch (MonoJumpInfoType patch_type)
@@ -366,6 +372,18 @@ emit_pointer (MonoAotCompile *acfg, const char *target)
        acfg->cur_section->cur_offset += sizeof (gpointer);
 }
 
+static void
+emit_int16 (MonoAotCompile *acfg, int value)
+{
+       guint8 *data;
+       emit_ensure_buffer (acfg->cur_section, 2);
+       data = acfg->cur_section->data + acfg->cur_section->cur_offset;
+       acfg->cur_section->cur_offset += 2;
+       /* FIXME: little endian */
+       data [0] = value;
+       data [1] = value >> 8;
+}
+
 static void
 emit_int32 (MonoAotCompile *acfg, int value)
 {
@@ -1369,7 +1387,21 @@ emit_bytes (MonoAotCompile *acfg, const guint8* buf, int size)
        }
 }
 
-static void
+static inline void
+emit_int16 (MonoAotCompile *acfg, int value)
+{
+       if (acfg->mode != EMIT_WORD) {
+               acfg->mode = EMIT_WORD;
+               acfg->col_count = 0;
+       }
+       if ((acfg->col_count++ % 8) == 0)
+               fprintf (acfg->fp, "\n\t.word ");
+       else
+               fprintf (acfg->fp, ", ");
+       fprintf (acfg->fp, "%d", value);
+}
+
+static inline void
 emit_int32 (MonoAotCompile *acfg, int value)
 {
        if (acfg->mode != EMIT_LONG) {
@@ -1555,13 +1587,22 @@ static void
 encode_klass_info (MonoAotCompile *cfg, MonoClass *klass, guint8 *buf, guint8 **endbuf)
 {
        if (!klass->type_token) {
+               guint32 token;
+
                /* Array class */
                g_assert (klass->rank > 0);
-               g_assert (klass->element_class->type_token);
                encode_value (MONO_TOKEN_TYPE_DEF, buf, &buf);
                encode_value (get_image_index (cfg, klass->image), buf, &buf);
-               g_assert (mono_metadata_token_code (klass->element_class->type_token) == MONO_TOKEN_TYPE_DEF);
-               encode_value (klass->element_class->type_token - MONO_TOKEN_TYPE_DEF, buf, &buf);
+               token = klass->element_class->type_token;
+               if (!token) {
+                       /* <Type>[][] */
+                       g_assert (klass->element_class->rank);
+                       encode_value (0, buf, &buf);
+                       encode_value (klass->element_class->rank, buf, &buf);
+                       token = klass->element_class->element_class->type_token;
+               }
+               g_assert (mono_metadata_token_code (token) == MONO_TOKEN_TYPE_DEF);
+               encode_value (token - MONO_TOKEN_TYPE_DEF, buf, &buf);
                encode_value (klass->rank, buf, &buf);
        }
        else {
@@ -1894,14 +1935,11 @@ encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info, guint8 *buf, guint
                guint32 image_index = get_image_index (acfg, patch_info->data.token->image);
                guint32 token = patch_info->data.token->token;
                g_assert (mono_metadata_token_code (token) == MONO_TOKEN_STRING);
-               /* 
-                * An optimization would be to emit shared code for ldstr 
-                * statements followed by a throw.
-                */
                encode_value (image_index, p, &p);
                encode_value (patch_info->data.token->token - MONO_TOKEN_STRING, p, &p);
                break;
        }
+       case MONO_PATCH_INFO_RVA:
        case MONO_PATCH_INFO_DECLSEC:
        case MONO_PATCH_INFO_LDTOKEN:
        case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
@@ -2072,6 +2110,15 @@ emit_method_info (MonoAotCompile *acfg, MonoCompile *cfg)
                        continue;
                }
 
+               if ((patch_info->type == MONO_PATCH_INFO_METHOD) ||
+                       (patch_info->type == MONO_PATCH_INFO_INTERNAL_METHOD) ||
+                       (patch_info->type == MONO_PATCH_INFO_WRAPPER) ||
+                       (patch_info->type == MONO_PATCH_INFO_CLASS_INIT)) {
+                       /* Calls are made through the PLT */
+                       patch_info->type = MONO_PATCH_INFO_NONE;
+                       continue;
+               }
+
                n_patches ++;
        }
 
@@ -2110,7 +2157,7 @@ emit_method_info (MonoAotCompile *acfg, MonoCompile *cfg)
                for (pindex = 0; pindex < patches->len; ++pindex) {
                        patch_info = g_ptr_array_index (patches, pindex);
                        if (patch_info->type != MONO_PATCH_INFO_NONE) {
-                               printf ("\t%s", patch_types [patch_info->type]);
+                               printf ("\t%s", get_patch_name (patch_info->type));
                                if (patch_info->type == MONO_PATCH_INFO_VTABLE)
                                        printf (": %s\n", patch_info->data.klass->name);
                                else
@@ -2228,7 +2275,9 @@ emit_klass_info (MonoAotCompile *acfg, guint32 token)
 
        no_special_static = !mono_class_has_special_static_fields (klass);
 
-       if (1) {
+       if (klass->generic_container) {
+               encode_value (-1, p, &p);
+       } else {
                encode_value (klass->vtable_size, p, &p);
                encode_value ((no_special_static << 7) | (klass->has_static_refs << 6) | (klass->has_references << 5) | ((klass->blittable << 4) | (klass->nested_classes ? 1 : 0) << 3) | (klass->has_cctor << 2) | (klass->has_finalize << 1) | klass->ghcimpl, p, &p);
                if (klass->has_cctor)
@@ -2494,6 +2543,11 @@ compile_method (MonoAotCompile *acfg, int index)
                return;
        }
 
+       if (mono_method_signature (method)->has_type_parameters || method->klass->generic_container) {
+               acfg->stats.genericcount ++;
+               return;
+       }
+
        /*
         * Since these methods are the only ones which are compiled with
         * AOT support, and they are not used by runtime startup/shutdown code,
@@ -2515,11 +2569,14 @@ compile_method (MonoAotCompile *acfg, int index)
 
        skip = FALSE;
        for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
-               if (patch_info->type == MONO_PATCH_INFO_ABS) {
+               switch (patch_info->type) {
+               case MONO_PATCH_INFO_ABS:
                        /* unable to handle this */
                        //printf ("Skip (abs addr):   %s %d\n", mono_method_full_name (method, TRUE), patch_info->type);
                        skip = TRUE;    
                        break;
+               default:
+                       break;
                }
        }
 
@@ -2529,6 +2586,42 @@ compile_method (MonoAotCompile *acfg, int index)
                return;
        }
 
+       /* 
+        * We can't currently handle instantinated generic types/methods
+        * since we save typedef/methoddef tokens, instead of typespec/methodref/methodspec 
+        * tokens.
+        */
+       for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
+               switch (patch_info->type) {
+               case MONO_PATCH_INFO_METHOD:
+               case MONO_PATCH_INFO_METHODCONST:
+                       /* Methods of instantinated generic types */
+                       if (patch_info->data.method->klass->generic_class)
+                               skip = TRUE;
+                       /* Instantinated generic methods */
+                       if (mono_method_signature (patch_info->data.method)->is_inflated)
+                               skip = TRUE;
+                       break;
+               case MONO_PATCH_INFO_VTABLE:
+               case MONO_PATCH_INFO_CLASS:
+               case MONO_PATCH_INFO_IID:
+               case MONO_PATCH_INFO_ADJUSTED_IID:
+               case MONO_PATCH_INFO_CLASS_INIT:
+                       if (patch_info->data.klass->generic_class)
+                               skip = TRUE;
+                       break;
+                       /* FIXME: Add more types of patches */
+               default:
+                       break;
+               }
+       }
+
+       if (skip) {
+               acfg->stats.genericcount++;
+               mono_destroy_compile (cfg);
+               return;
+       }
+
        skip = FALSE;
        for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
                if (patch_info->type == MONO_PATCH_INFO_METHOD_JUMP) {
@@ -2599,7 +2692,7 @@ compile_method (MonoAotCompile *acfg, int index)
                case MONO_PATCH_INFO_IID:
                case MONO_PATCH_INFO_ADJUSTED_IID:
                        if (!patch_info->data.klass->type_token)
-                               if (!patch_info->data.klass->element_class->type_token)
+                               if (!patch_info->data.klass->element_class->type_token && !(patch_info->data.klass->element_class->rank && patch_info->data.klass->element_class->element_class->type_token))
                                        skip = TRUE;
                        break;
                default:
@@ -2701,6 +2794,7 @@ load_profile_files (MonoAotCompile *acfg)
                res = fscanf (infile, "%32s\n", ver);
                if ((res != 1) || strcmp (ver, "#VER:1") != 0) {
                        printf ("Profile file has wrong version or invalid.\n");
+                       fclose (infile);
                        continue;
                }
 
@@ -2714,6 +2808,7 @@ load_profile_files (MonoAotCompile *acfg)
                        if (!g_list_find (acfg->method_order, GUINT_TO_POINTER (method_index)))
                                acfg->method_order = g_list_append (acfg->method_order, GUINT_TO_POINTER (method_index));
                }
+               fclose (infile);
        }
 
        /* Add missing methods */
@@ -2760,6 +2855,7 @@ alloc_got_slots (MonoAotCompile *acfg)
                                case MONO_PATCH_INFO_DECLSEC:
                                case MONO_PATCH_INFO_LDTOKEN:
                                case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
+                               case MONO_PATCH_INFO_RVA:
                                        get_shared_got_offset (acfg, ji);
                                        break;
                                default:
@@ -3025,19 +3121,21 @@ emit_class_name_table (MonoAotCompile *acfg)
        emit_label (acfg, symbol);
 
        /* FIXME: Optimize memory usage */
-       emit_int32 (acfg, table_size);
+       g_assert (table_size < 65000);
+       emit_int16 (acfg, table_size);
+       g_assert (table->len < 65000);
        for (i = 0; i < table->len; ++i) {
                ClassNameTableEntry *entry = g_ptr_array_index (table, i);
 
                if (entry == NULL) {
-                       emit_int32 (acfg, 0);
-                       emit_int32 (acfg, 0);
+                       emit_int16 (acfg, 0);
+                       emit_int16 (acfg, 0);
                } else {
-                       emit_int32 (acfg, entry->token);
+                       emit_int16 (acfg, mono_metadata_token_index (entry->token));
                        if (entry->next)
-                               emit_int32 (acfg, entry->next->index);
+                               emit_int16 (acfg, entry->next->index);
                        else
-                               emit_int32 (acfg, 0);
+                               emit_int16 (acfg, 0);
                }
        }
 }
@@ -3206,6 +3304,7 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
 
        load_profile_files (acfg);
 
+#if 0
        if (mono_defaults.generic_nullable_class) {
                /* 
                 * FIXME: Its hard to skip generic methods or methods which use generics.
@@ -3213,6 +3312,7 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
                printf ("Error: Can't AOT Net 2.0 assemblies.\n");
                return 1;
        }
+#endif
 
        emit_start (acfg);
 
@@ -3274,7 +3374,7 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
        printf ("GOT slot distribution:\n");
        for (i = 0; i < MONO_PATCH_INFO_NONE; ++i)
                if (acfg->stats.got_slot_types [i])
-                       printf ("\t%s: %d\n", patch_types [i], acfg->stats.got_slot_types [i]);
+                       printf ("\t%s: %d\n", get_patch_name (i), acfg->stats.got_slot_types [i]);
 
        return 0;
 }