2005-02-05 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mono / mini / aot.c
index c36c4065af16ed26432487b99dc41d5268ff7886..2850065c92558d0671c69220006923ddd8e58704 100644 (file)
 
 #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 {
        char *aot_name;
        /* Optimization flags used to compile the module */
        guint32 opts;
-       /* Maps MonoMethods to MonoAotMethodInfos */
-       GHashTable *methods;
        /* Pointer to the Global Offset Table */
        gpointer *got;
        guint32 got_size;
@@ -81,6 +73,8 @@ typedef struct MonoAotModule {
        guint32 *code_offsets;
        guint8 *method_infos;
        guint32 *method_info_offsets;
+       guint8 *class_infos;
+       guint32 *class_info_offsets;
 } MonoAotModule;
 
 typedef struct MonoAotOptions {
@@ -90,6 +84,7 @@ typedef struct MonoAotOptions {
 } MonoAotOptions;
 
 typedef struct MonoAotCompile {
+       MonoImage *image;
        FILE *fp;
        GHashTable *icall_hash;
        GPtrArray *icall_table;
@@ -248,6 +243,24 @@ decode_field_info (MonoAotModule *module, char *buf, char **endbuf)
        return mono_class_get_field (klass, token);
 }
 
+static inline MonoImage*
+decode_method_ref (MonoAotModule *module, guint32 *token, char *buf, char **endbuf)
+{
+       guint32 image_index, value;
+       MonoImage *image;
+
+       value = decode_value (buf, &buf);
+       *endbuf = buf;
+       image_index = value >> 24;
+       *token = MONO_TOKEN_METHOD_DEF | (value & 0xffffff);
+
+       image = load_image (module, image_index);
+       if (!image)
+               return NULL;
+       else
+               return image;
+}
+
 G_GNUC_UNUSED
 static void
 make_writable (guint8* addr, guint32 len)
@@ -442,7 +455,6 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data)
 
        info = g_new0 (MonoAotModule, 1);
        info->aot_name = aot_name;
-       info->methods = g_hash_table_new (NULL, NULL);
 #ifdef MONO_ARCH_HAVE_PIC_AOT
        info->got = got;
        info->got_size = *got_size_ptr;
@@ -511,6 +523,8 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data)
        g_module_symbol (assembly->aot_module, "methods", (gpointer*)&info->code);
        g_module_symbol (assembly->aot_module, "method_info_offsets", (gpointer*)&info->method_info_offsets);
        g_module_symbol (assembly->aot_module, "method_infos", (gpointer*)&info->method_infos);
+       g_module_symbol (assembly->aot_module, "class_infos", (gpointer*)&info->class_infos);
+       g_module_symbol (assembly->aot_module, "class_info_offsets", (gpointer*)&info->class_info_offsets);
 
        EnterCriticalSection (&aot_mutex);
        g_hash_table_insert (aot_modules, assembly, info);
@@ -532,6 +546,131 @@ mono_aot_init (void)
        if (getenv ("MONO_AOT_CACHE"))
                use_aot_cache = TRUE;
 }
+
+static gboolean
+decode_cached_class_info (MonoAotModule *module, MonoCachedClassInfo *info, char *buf, char **endbuf)
+{
+       guint32 flags;
+
+       info->vtable_size = decode_value (buf, &buf);
+       flags = decode_value (buf, &buf);
+       info->ghcimpl = (flags >> 0) & 0x1;
+       info->has_finalize = (flags >> 1) & 0x1;
+       info->has_cctor = (flags >> 2) & 0x1;
+       if (info->has_cctor) {
+               MonoImage *cctor_image = decode_method_ref (module, &info->cctor_token, buf, &buf);
+               if (!cctor_image)
+                       return FALSE;
+       }
+       if (info->has_finalize) {
+               info->finalize_image = decode_method_ref (module, &info->finalize_token, buf, &buf);
+               if (!info->finalize_image)
+                       return FALSE;
+       }
+
+       *endbuf = buf;
+
+       return TRUE;
+}      
+
+gboolean
+mono_aot_init_vtable (MonoVTable *vtable)
+{
+       int i;
+       MonoAotModule *aot_module;
+       MonoClass *klass = vtable->klass;
+       guint8 *info;
+       MonoCachedClassInfo class_info;
+       char *p;
+       gboolean err;
+
+       if (MONO_CLASS_IS_INTERFACE (klass) || klass->rank || !klass->image->assembly->aot_module)
+               return FALSE;
+
+       EnterCriticalSection (&aot_mutex);
+
+       aot_module = (MonoAotModule*) g_hash_table_lookup (aot_modules, klass->image->assembly);
+       if (!aot_module) {
+               LeaveCriticalSection (&aot_mutex);
+               return FALSE;
+       }
+
+       info = &aot_module->class_infos [aot_module->class_info_offsets [mono_metadata_token_index (klass->type_token) - 1]];
+       p = (char*)info;
+
+       err = decode_cached_class_info (aot_module, &class_info, p, &p);
+       if (!err) {
+               LeaveCriticalSection (&aot_mutex);
+               return FALSE;
+       }
+
+       //printf ("VT0: %s.%s %d\n", klass->name_space, klass->name, vtable_size);
+       for (i = 0; i < class_info.vtable_size; ++i) {
+               guint32 image_index, token, value;
+               MonoImage *image;
+               MonoMethod *m;
+
+               vtable->vtable [i] = 0;
+
+               value = decode_value (p, &p);
+               if (!value)
+                       continue;
+
+               image_index = value >> 24;
+               token = MONO_TOKEN_METHOD_DEF | (value & 0xffffff);
+
+               image = load_image (aot_module, image_index);
+               if (!image) {
+                       LeaveCriticalSection (&aot_mutex);
+                       return FALSE;
+               }
+
+#ifdef MONO_ARCH_HAVE_CREATE_TRAMPOLINE_FROM_TOKEN
+               vtable->vtable [i] = mono_create_jit_trampoline_from_token (image, token);
+#else
+               m = mono_get_method (image, token, NULL);
+               g_assert (m);
+
+               //printf ("M: %d %p %s\n", i, &(vtable->vtable [i]), mono_method_full_name (m, TRUE));
+               vtable->vtable [i] = mono_create_jit_trampoline (m);
+#endif
+       }
+
+       LeaveCriticalSection (&aot_mutex);
+
+       return TRUE;
+}
+
+gboolean
+mono_aot_get_cached_class_info (MonoClass *klass, MonoCachedClassInfo *res)
+{
+       MonoAotModule *aot_module;
+       char *p;
+       gboolean err;
+
+       if (MONO_CLASS_IS_INTERFACE (klass) || klass->rank || !klass->image->assembly->aot_module)
+               return FALSE;
+
+       EnterCriticalSection (&aot_mutex);
+
+       aot_module = (MonoAotModule*) g_hash_table_lookup (aot_modules, klass->image->assembly);
+       if (!aot_module) {
+               LeaveCriticalSection (&aot_mutex);
+               return FALSE;
+       }
+
+       p = &aot_module->class_infos [aot_module->class_info_offsets [mono_metadata_token_index (klass->type_token) - 1]];
+
+       err = decode_cached_class_info (aot_module, res, p, &p);
+       if (!err) {
+               LeaveCriticalSection (&aot_mutex);
+               return FALSE;
+       }
+
+       LeaveCriticalSection (&aot_mutex);
+
+       return TRUE;
+}
  
 static MonoJitInfo *
 mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method)
@@ -542,9 +681,6 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method)
        guint8 *code = NULL;
        guint8 *info;
        MonoAotModule *aot_module;
-       MonoAotMethod *minfo;
-       MonoJitInfo *jinfo;
-       MonoMethodHeader *header;
 
        if (!module)
                return NULL;
@@ -561,8 +697,6 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method)
                (method->flags & METHOD_ATTRIBUTE_ABSTRACT))
                return NULL;
        
-       header = mono_method_get_header (method);
-       
        aot_module = (MonoAotModule*) g_hash_table_lookup (aot_modules, ass);
 
        g_assert (klass->inited);
@@ -571,28 +705,15 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method)
                /* Non shared AOT code can't be used in other appdomains */
                return NULL;
 
-       minfo = g_hash_table_lookup (aot_module->methods, method);
-       /* 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));
-               if (jinfo->clauses) {
-                       jinfo->clauses = 
-                               mono_mempool_alloc0 (domain->mp, sizeof (MonoJitExceptionInfo) * header->num_clauses);
-                       memcpy (jinfo->clauses, minfo->info->clauses, sizeof (MonoJitExceptionInfo) * header->num_clauses);
-               }
-
-               return jinfo;
-       }
-
        if (aot_module->out_of_date)
                return NULL;
 
        if (aot_module->code_offsets [mono_metadata_token_index (method->token) - 1] == 0xffffffff) {
-               mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT NOT FOUND: %s.\n", mono_method_full_name (method, TRUE));
+               if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT)) {
+                       char *full_name = mono_method_full_name (method, TRUE);
+                       mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT NOT FOUND: %s.\n", full_name);
+                       g_free (full_name);
+               }
                return NULL;
        }
 
@@ -616,20 +737,14 @@ mono_aot_load_method (MonoDomain *domain, MonoAotModule *aot_module, MonoMethod
        MonoClass *klass = method->klass;
        MonoJumpInfo *patch_info = NULL;
        guint code_len, used_int_regs, used_strings;
-       MonoAotMethod *minfo;
        MonoJitInfo *jinfo;
-       MonoMethodHeader *header = mono_method_get_header (method);
        MonoMemPool *mp;
        GPtrArray *patches;
        int i, pindex, got_index;
        gboolean non_got_patches, keep_patches = TRUE;
+       gboolean has_clauses;
        char *p;
 
-       minfo = g_new0 (MonoAotMethod, 1);
-
-       minfo->domain = domain;
-       jinfo = mono_mempool_alloc0 (domain->mp, sizeof (MonoJitInfo));
-
        p = (char*)info;
        code_len = decode_value (p, &p);
        used_int_regs = decode_value (p, &p);
@@ -642,12 +757,18 @@ mono_aot_load_method (MonoDomain *domain, MonoAotModule *aot_module, MonoMethod
                code = code2;
        }
 
-       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);
+       if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT)) {
+               char *full_name = mono_method_full_name (method, TRUE);
+               mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT FOUND AOT compiled code for %s %p - %p %p\n", full_name, code, code + code_len, info);
+               g_free (full_name);
+       }
 
        /* Exception table */
-       if (header->num_clauses) {
-               jinfo->clauses = 
-                       mono_mempool_alloc0 (domain->mp, sizeof (MonoJitExceptionInfo) * header->num_clauses);
+       has_clauses = decode_value (p, &p);
+       if (has_clauses) {
+               MonoMethodHeader *header = mono_method_get_header (method);
+               jinfo = 
+                       mono_mempool_alloc0 (domain->mp, sizeof (MonoJitInfo) + (sizeof (MonoJitExceptionInfo) * header->num_clauses));
                jinfo->num_clauses = header->num_clauses;
 
                for (i = 0; i < header->num_clauses; ++i) {
@@ -667,6 +788,8 @@ mono_aot_load_method (MonoDomain *domain, MonoAotModule *aot_module, MonoMethod
                        ei->handler_start = code + decode_value (p, &p);
                }
        }
+       else
+               jinfo = mono_mempool_alloc0 (domain->mp, sizeof (MonoJitInfo));
 
        if (aot_module->opts & MONO_OPT_SHARED)
                used_strings = decode_value (p, &p);
@@ -804,6 +927,8 @@ mono_aot_load_method (MonoDomain *domain, MonoAotModule *aot_module, MonoMethod
                                }
                                case MONO_WRAPPER_LDFLD:
                                case MONO_WRAPPER_STFLD:
+                               case MONO_WRAPPER_LDFLD_REMOTE:
+                               case MONO_WRAPPER_STFLD_REMOTE:
                                case MONO_WRAPPER_ISINST: {
                                        MonoClass *klass = decode_klass_info (aot_module, p, &p);
                                        if (!klass)
@@ -813,6 +938,8 @@ mono_aot_load_method (MonoDomain *domain, MonoAotModule *aot_module, MonoMethod
                                                ji->data.method = mono_marshal_get_ldfld_wrapper (&klass->byval_arg);
                                        else if (wrapper_type == MONO_WRAPPER_STFLD)
                                                ji->data.method = mono_marshal_get_stfld_wrapper (&klass->byval_arg);
+                                       else if (wrapper_type == MONO_WRAPPER_LDFLD_REMOTE)
+                                               ji->data.method = mono_marshal_get_ldfld_remote_wrapper (klass);
                                        else
                                                ji->data.method = mono_marshal_get_isinst (klass);
                                        break;
@@ -835,7 +962,6 @@ mono_aot_load_method (MonoDomain *domain, MonoAotModule *aot_module, MonoMethod
                        case MONO_PATCH_INFO_INTERNAL_METHOD:
                                ji->data.name = aot_module->icall_table [decode_value (p, &p)];
                                g_assert (ji->data.name);
-                               //printf ("A: %s.\n", ji->data.name);
                                break;
                        case MONO_PATCH_INFO_SWITCH:
                                ji->data.table = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoBBTable));
@@ -845,17 +971,19 @@ mono_aot_load_method (MonoDomain *domain, MonoAotModule *aot_module, MonoMethod
                                for (i = 0; i < ji->data.table->table_size; i++)
                                        table [i] = (gpointer)(gssize)decode_value (p, &p);
                                break;
-                       case MONO_PATCH_INFO_R4:
-                               ji->data.target = mono_mempool_alloc0 (mp, sizeof (float));
+                       case MONO_PATCH_INFO_R4: {
                                guint32 val;
 
+                               ji->data.target = mono_mempool_alloc0 (mp, sizeof (float));
                                val = decode_value (p, &p);
                                *(float*)ji->data.target = *(float*)&val;
                                break;
+                       }
                        case MONO_PATCH_INFO_R8: {
-                               ji->data.target = mono_mempool_alloc0 (mp, sizeof (double));
                                guint32 val [2];
 
+                               ji->data.target = mono_mempool_alloc0 (mp, sizeof (double));
+
                                val [0] = decode_value (p, &p);
                                val [1] = decode_value (p, &p);
                                *(double*)ji->data.target = *(double*)val;
@@ -948,9 +1076,6 @@ mono_aot_load_method (MonoDomain *domain, MonoAotModule *aot_module, MonoMethod
                jinfo->domain_neutral = (aot_module->opts & MONO_OPT_SHARED) != 0;
 #endif
 
-               minfo->info = jinfo;
-               g_hash_table_insert (aot_module->methods, method, minfo);
-
                return jinfo;
        }
 
@@ -1210,6 +1335,18 @@ encode_field_info (MonoAotCompile *cfg, MonoClassField *field, char *buf, char *
        *endbuf = buf;
 }
 
+static void
+encode_method_ref (MonoAotCompile *acfg, MonoMethod *method, char *buf, char **endbuf)
+{
+       guint32 image_index = get_image_index (acfg, method->klass->image);
+       guint32 token = method->token;
+       g_assert (image_index < 256);
+       g_assert (mono_metadata_token_table (token) == MONO_TABLE_METHOD);
+
+       encode_value ((image_index << 24) + (mono_metadata_token_index (token)), buf, &buf);
+       *endbuf = buf;
+}
+
 static gint
 compare_patches (gconstpointer a, gconstpointer b)
 {
@@ -1247,8 +1384,6 @@ emit_method_code (MonoAotCompile *acfg, MonoCompile *cfg)
        code = cfg->native_code;
        header = mono_method_get_header (method);
 
-       emit_section_change (tmpfp, ".text", 0);
-
        /* Make the labels local */
        mname = g_strdup_printf (".Lm_%x", mono_metadata_token_index (method->token));
        mname_p = g_strdup_printf ("%s_p", mname);
@@ -1381,6 +1516,7 @@ emit_method_info (MonoAotCompile *acfg, MonoCompile *cfg)
        encode_value (cfg->used_int_regs, p, &p);
 
        /* Exception table */
+       encode_value (header->num_clauses ? 1 : 0, p, &p);
        if (header->num_clauses) {
                MonoJitInfo *jinfo = cfg->jit_info;
 
@@ -1489,15 +1625,9 @@ emit_method_info (MonoAotCompile *acfg, MonoCompile *cfg)
                }
                case MONO_PATCH_INFO_METHODCONST:
                case MONO_PATCH_INFO_METHOD:
-               case MONO_PATCH_INFO_METHOD_JUMP: {
-                       guint32 image_index = get_image_index (acfg, patch_info->data.method->klass->image);
-                       guint32 token = patch_info->data.method->token;
-                       g_assert (image_index < 256);
-                       g_assert (mono_metadata_token_table (token) == MONO_TABLE_METHOD);
-
-                       encode_value ((image_index << 24) + (mono_metadata_token_index (token)), p, &p);
+               case MONO_PATCH_INFO_METHOD_JUMP:
+                       encode_method_ref (acfg, patch_info->data.method, p, &p);
                        break;
-               }
                case MONO_PATCH_INFO_INTERNAL_METHOD: {
                        guint32 icall_index;
 
@@ -1577,6 +1707,8 @@ emit_method_info (MonoAotCompile *acfg, MonoCompile *cfg)
                        case MONO_WRAPPER_PROXY_ISINST:
                        case MONO_WRAPPER_LDFLD:
                        case MONO_WRAPPER_STFLD:
+                       case MONO_WRAPPER_LDFLD_REMOTE:
+                       case MONO_WRAPPER_STFLD_REMOTE:
                        case MONO_WRAPPER_ISINST: {
                                MonoClass *proxy_class = (MonoClass*)mono_marshal_method_from_wrapper (patch_info->data.method);
                                encode_klass_info (acfg, proxy_class, p, &p);
@@ -1606,7 +1738,6 @@ emit_method_info (MonoAotCompile *acfg, MonoCompile *cfg)
 
        /* Emit method info */
 
-       emit_section_change (tmpfp, ".text", 1);
        emit_label (tmpfp, mname_p);
 
        g_assert (p - buf < buf_size);
@@ -1622,6 +1753,60 @@ emit_method_info (MonoAotCompile *acfg, MonoCompile *cfg)
        g_free (mname_p);
 }
 
+static void
+emit_klass_info (MonoAotCompile *acfg, guint32 token)
+{
+       MonoClass *klass = mono_class_get (acfg->image, token);
+       char *p, *buf;
+       int i, buf_size;
+       char *label;
+       FILE *tmpfp = acfg->fp;
+
+       buf_size = 10240;
+       p = buf = g_malloc (buf_size);
+
+       g_assert (klass);
+
+       mono_class_init (klass);
+
+       /* 
+        * Emit all the information which is required for creating vtables so
+        * the runtime does not need to create the MonoMethod structures which
+        * take up a lot of space.
+        */
+
+       if (!MONO_CLASS_IS_INTERFACE (klass)) {
+               encode_value (klass->vtable_size, p, &p);
+               encode_value ((klass->has_cctor << 2) | (klass->has_finalize << 1) | klass->ghcimpl, p, &p);
+               if (klass->has_cctor)
+                       encode_method_ref (acfg, mono_class_get_cctor (klass), p, &p);
+               if (klass->has_finalize)
+                       encode_method_ref (acfg, mono_class_get_finalizer (klass), p, &p);
+
+               for (i = 0; i < klass->vtable_size; ++i) {
+                       MonoMethod *cm = klass->vtable [i];
+
+                       if (cm)
+                               encode_method_ref (acfg, cm, p, &p);
+                       else
+                               encode_value (0, p, &p);
+               }
+       }
+
+       /* Emit the info */
+       label = g_strdup_printf (".LK_I_%x", token - MONO_TOKEN_TYPE_DEF - 1);
+       emit_label (tmpfp, label);
+
+       g_assert (p - buf < buf_size);
+       for (i = 0; i < p - buf; ++i) {
+               if ((i % 32) == 0)
+                       fprintf (tmpfp, "\n.byte ");
+               fprintf (tmpfp, "%s%d", ((i % 32) == 0) ? "" : ",", (unsigned int) buf [i]);
+       }
+       fprintf (tmpfp, "\n");
+       g_free (buf);
+}
+
 static gboolean
 str_begins_with (const char *str1, const char *str2)
 {
@@ -1675,6 +1860,7 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
        acfg->icall_table = g_ptr_array_new ();
        acfg->image_hash = g_hash_table_new (NULL, NULL);
        acfg->image_table = g_ptr_array_new ();
+       acfg->image = image;
 
        mono_aot_parse_options (aot_options, &acfg->aot_opts);
 
@@ -1743,7 +1929,7 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
                g_assert (cfg);
 
                if (cfg->disable_aot) {
-                       printf ("Skip (other): %s\n", mono_method_full_name (method, TRUE));
+                       //printf ("Skip (other): %s\n", mono_method_full_name (method, TRUE));
                        ocount++;
                        continue;
                }
@@ -1777,6 +1963,8 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
                                case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK:
                                case MONO_WRAPPER_STFLD:
                                case MONO_WRAPPER_LDFLD:
+                               case MONO_WRAPPER_LDFLD_REMOTE:
+                               case MONO_WRAPPER_STFLD_REMOTE:
                                case MONO_WRAPPER_STELEMREF:
                                case MONO_WRAPPER_ISINST:
                                case MONO_WRAPPER_PROXY_ISINST:
@@ -1833,17 +2021,50 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
        }
 
        /* Emit code */
+       emit_section_change (tmpfp, ".text", 0);
        for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
                if (cfgs [i])
                        emit_method_code (acfg, cfgs [i]);
        }
 
        /* Emit method info */
+       emit_section_change (tmpfp, ".text", 1);
        for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
                if (cfgs [i])
                        emit_method_info (acfg, cfgs [i]);
        }
 
+       /* Emit class info */
+
+       symbol = g_strdup_printf ("class_infos");
+       emit_section_change (tmpfp, ".text", 1);
+       emit_global (tmpfp, symbol, FALSE);
+       emit_alignment (tmpfp, 8);
+       emit_label (tmpfp, symbol);
+
+       for (i = 0; i < image->tables [MONO_TABLE_TYPEDEF].rows; ++i)
+               emit_klass_info (acfg, MONO_TOKEN_TYPE_DEF | (i + 1));
+
+       symbol = g_strdup_printf ("class_info_offsets");
+       emit_section_change (tmpfp, ".text", 1);
+       emit_global (tmpfp, symbol, FALSE);
+       emit_alignment (tmpfp, 8);
+       emit_label(tmpfp, symbol);
+
+       for (i = 0; i < image->tables [MONO_TABLE_TYPEDEF].rows; ++i) {
+               const char *sep;
+               if ((i % 32) == 0) {
+                       fprintf (tmpfp, "\n.long ");
+                       sep = "";
+               }
+               else
+                       sep = ",";
+
+               symbol = g_strdup_printf (".LK_I_%x", i);
+               fprintf (tmpfp, "%s%s - class_infos", sep, symbol);
+       }
+       fprintf (tmpfp, "\n");
+
        /*
         * The icall and image tables are small but referenced in a lot of places.
         * So we emit them at once, and reference their elements by an index.