2006-04-20 Geoff Norton <gnorton@customerdna.com>
[mono.git] / mono / mini / aot.c
1 /*
2  * aot.c: mono Ahead of Time compiler
3  *
4  * Author:
5  *   Dietmar Maurer (dietmar@ximian.com)
6  *   Zoltan Varga (vargaz@gmail.com)
7  *
8  * (C) 2002 Ximian, Inc.
9  */
10
11 #include "config.h"
12 #include <sys/types.h>
13 #include <unistd.h>
14 #include <fcntl.h>
15 #include <string.h>
16 #ifndef PLATFORM_WIN32
17 #include <sys/mman.h>
18 #else
19 #include <winsock2.h>
20 #include <windows.h>
21 #endif
22
23 #include <errno.h>
24 #include <sys/stat.h>
25 #include <limits.h>    /* for PAGESIZE */
26 #ifndef PAGESIZE
27 #define PAGESIZE 4096
28 #endif
29
30 #include <mono/metadata/tabledefs.h>
31 #include <mono/metadata/class.h>
32 #include <mono/metadata/object.h>
33 #include <mono/metadata/tokentype.h>
34 #include <mono/metadata/appdomain.h>
35 #include <mono/metadata/debug-helpers.h>
36 #include <mono/metadata/assembly.h>
37 #include <mono/metadata/metadata-internals.h>
38 #include <mono/metadata/marshal.h>
39 #include <mono/utils/mono-logger.h>
40 #include "mono/utils/mono-compiler.h"
41
42 #include "mini.h"
43
44 #ifndef DISABLE_AOT
45
46 #ifdef PLATFORM_WIN32
47 #define SHARED_EXT ".dll"
48 #elif defined(__ppc__) && defined(__MACH__)
49 #define SHARED_EXT ".dylib"
50 #else
51 #define SHARED_EXT ".so"
52 #endif
53
54 #if defined(sparc) || defined(__ppc__)
55 #define AS_STRING_DIRECTIVE ".asciz"
56 #else
57 /* GNU as */
58 #define AS_STRING_DIRECTIVE ".string"
59 #endif
60
61 #define N_RESERVED_GOT_SLOTS 1
62 #define ICALL_GOT_SLOTS_START_INDEX N_RESERVED_GOT_SLOTS
63
64 #define ALIGN_PTR_TO(ptr,align) (gpointer)((((gssize)(ptr)) + (align - 1)) & (~(align - 1)))
65 #define ROUND_DOWN(VALUE,SIZE)  ((VALUE) & ~((SIZE) - 1))
66
67 typedef struct MonoAotModule {
68         char *aot_name;
69         /* Optimization flags used to compile the module */
70         guint32 opts;
71         /* Pointer to the Global Offset Table */
72         gpointer *got;
73         guint32 got_size;
74         char **icall_table;
75         MonoAssemblyName *image_names;
76         char **image_guids;
77         MonoImage **image_table;
78         gboolean out_of_date;
79         guint8 *mem_begin;
80         guint8 *mem_end;
81         guint8 *code;
82         guint8 *code_end;
83         guint32 *code_offsets;
84         guint8 *method_infos;
85         guint32 *method_info_offsets;
86         guint8 *ex_infos;
87         guint32 *ex_info_offsets;
88         guint32 *method_order;
89         guint32 *method_order_end;
90         guint8 *class_infos;
91         guint32 *class_info_offsets;
92         guint32 *methods_loaded;
93 } MonoAotModule;
94
95 typedef struct MonoAotOptions {
96         char *outfile;
97         gboolean save_temps;
98         gboolean write_symbols;
99 } MonoAotOptions;
100
101 typedef struct MonoAotCompile {
102         MonoImage *image;
103         MonoCompile **cfgs;
104         FILE *fp;
105         GHashTable *icall_hash;
106         GHashTable *icall_to_got_offset_hash;
107         GPtrArray *icall_table;
108         GHashTable *image_hash;
109         GPtrArray *image_table;
110         GList *method_order;
111         guint32 got_offset;
112         guint32 *method_got_offsets;
113         MonoAotOptions aot_opts;
114         guint32 nmethods;
115         guint32 opts;
116         int ccount, mcount, lmfcount, abscount, wrappercount, ocount;
117         int code_size, info_size, ex_info_size, got_size, class_info_size;
118 } MonoAotCompile;
119
120 static GHashTable *aot_modules;
121 #define mono_aot_lock() EnterCriticalSection (&aot_mutex)
122 #define mono_aot_unlock() LeaveCriticalSection (&aot_mutex)
123 static CRITICAL_SECTION aot_mutex;
124
125 /*
126  * Disabling this will make a copy of the loaded code and use the copy instead 
127  * of the original. This will place the caller and the callee close to each 
128  * other in memory, possibly improving cache behavior. Since the original
129  * code is in copy-on-write memory, this will not increase the memory usage
130  * of the runtime.
131  */
132 #ifdef MONO_ARCH_HAVE_PIC_AOT
133 static gboolean use_loaded_code = TRUE;
134 #else
135 static gboolean use_loaded_code = FALSE;
136 #endif
137
138 /*
139  * Whenever to AOT compile loaded assemblies on demand and store them in
140  * a cache under $HOME/.mono/aot-cache.
141  */
142 static gboolean use_aot_cache = FALSE;
143
144 /* For debugging */
145 static gint32 mono_last_aot_method = -1;
146
147 static gboolean make_unreadable = FALSE;
148 static guint32 n_pagefaults = 0;
149
150 static MonoJitInfo*
151 mono_aot_load_method (MonoDomain *domain, MonoAotModule *aot_module, MonoMethod *method, guint8 *code, guint8 *info, guint8 *ex_info);
152
153 static gboolean 
154 is_got_patch (MonoJumpInfoType patch_type)
155 {
156 #ifdef __x86_64__
157         return TRUE;
158 #elif defined(__i386__)
159         return TRUE;
160 #else
161         return FALSE;
162 #endif
163 }
164
165 /*****************************************************/
166 /*                 AOT RUNTIME                       */
167 /*****************************************************/
168
169 static MonoImage *
170 load_image (MonoAotModule *module, int index)
171 {
172         MonoAssembly *assembly;
173         MonoImageOpenStatus status;
174
175         if (module->image_table [index])
176                 return module->image_table [index];
177         if (module->out_of_date)
178                 return NULL;
179
180         assembly = mono_assembly_load (&module->image_names [index], NULL, &status);
181         if (!assembly) {
182                 module->out_of_date = TRUE;
183                 return NULL;
184         }
185
186         if (strcmp (assembly->image->guid, module->image_guids [index])) {
187                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT module %s is out of date (Older than dependency %s).\n", module->aot_name, module->image_names [index].name);
188                 module->out_of_date = TRUE;
189                 return NULL;
190         }
191
192         module->image_table [index] = assembly->image;
193         return assembly->image;
194 }
195
196
197 static inline gint32
198 decode_value (guint8 *ptr, guint8 **rptr)
199 {
200         guint8 b = *ptr;
201         gint32 len;
202         
203         if ((b & 0x80) == 0){
204                 len = b;
205                 ++ptr;
206         } else if ((b & 0x40) == 0){
207                 len = ((b & 0x3f) << 8 | ptr [1]);
208                 ptr += 2;
209         } else if (b != 0xff) {
210                 len = ((b & 0x1f) << 24) |
211                         (ptr [1] << 16) |
212                         (ptr [2] << 8) |
213                         ptr [3];
214                 ptr += 4;
215         }
216         else {
217                 len = (ptr [1] << 24) | (ptr [2] << 16) | (ptr [3] << 8) | ptr [4];
218                 ptr += 5;
219         }
220         if (rptr)
221                 *rptr = ptr;
222
223         //printf ("DECODE: %d.\n", len);
224         return len;
225 }
226
227 static MonoClass*
228 decode_klass_info (MonoAotModule *module, guint8 *buf, guint8 **endbuf)
229 {
230         MonoImage *image;
231         MonoClass *klass;
232         guint32 token, rank, image_index;
233
234         token = decode_value (buf, &buf);
235         if (token == 0) {
236                 *endbuf = buf;
237                 return NULL;
238         }
239         image_index = decode_value (buf, &buf);
240         image = load_image (module, image_index);
241         if (!image)
242                 return NULL;
243         if (mono_metadata_token_code (token) == 0) {
244                 klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF + token);
245         } else {
246                 token = MONO_TOKEN_TYPE_DEF + decode_value (buf, &buf);
247                 rank = decode_value (buf, &buf);
248                 klass = mono_class_get (image, token);
249                 g_assert (klass);
250                 klass = mono_array_class_get (klass, rank);
251         }
252         g_assert (klass);
253         mono_class_init (klass);
254
255         *endbuf = buf;
256         return klass;
257 }
258
259 static MonoClassField*
260 decode_field_info (MonoAotModule *module, guint8 *buf, guint8 **endbuf)
261 {
262         MonoClass *klass = decode_klass_info (module, buf, &buf);
263         guint32 token;
264
265         if (!klass)
266                 return NULL;
267
268         token = MONO_TOKEN_FIELD_DEF + decode_value (buf, &buf);
269
270         *endbuf = buf;
271
272         return mono_class_get_field (klass, token);
273 }
274
275 static inline MonoImage*
276 decode_method_ref (MonoAotModule *module, guint32 *token, guint8 *buf, guint8 **endbuf)
277 {
278         guint32 image_index, value;
279         MonoImage *image;
280
281         value = decode_value (buf, &buf);
282         *endbuf = buf;
283         image_index = value >> 24;
284         *token = MONO_TOKEN_METHOD_DEF | (value & 0xffffff);
285
286         image = load_image (module, image_index);
287         if (!image)
288                 return NULL;
289         else
290                 return image;
291 }
292
293 G_GNUC_UNUSED
294 static void
295 make_writable (guint8* addr, guint32 len)
296 {
297 #ifndef PLATFORM_WIN32
298         guint8 *page_start;
299         int pages, err;
300
301         page_start = (guint8 *) (((gssize) (addr)) & ~ (PAGESIZE - 1));
302         pages = (addr + len - page_start + PAGESIZE - 1) / PAGESIZE;
303         err = mprotect (page_start, pages * PAGESIZE, PROT_READ | PROT_WRITE | PROT_EXEC);
304         g_assert (err == 0);
305 #else
306         {
307                 DWORD oldp;
308                 g_assert (VirtualProtect (addr, len, PAGE_EXECUTE_READWRITE, &oldp) != 0);
309         }
310 #endif
311 }
312
313 static void
314 create_cache_structure (void)
315 {
316         const char *home;
317         char *tmp;
318         int err;
319
320         home = g_get_home_dir ();
321         if (!home)
322                 return;
323
324         tmp = g_build_filename (home, ".mono", NULL);
325         if (!g_file_test (tmp, G_FILE_TEST_IS_DIR)) {
326                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT creating directory %s", tmp);
327 #ifdef PLATFORM_WIN32
328                 err = mkdir (tmp);
329 #else
330                 err = mkdir (tmp, 0777);
331 #endif
332                 if (err) {
333                         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT failed: %s", g_strerror (errno));
334                         g_free (tmp);
335                         return;
336                 }
337         }
338         g_free (tmp);
339         tmp = g_build_filename (home, ".mono", "aot-cache", NULL);
340         if (!g_file_test (tmp, G_FILE_TEST_IS_DIR)) {
341                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT creating directory %s", tmp);
342 #ifdef PLATFORM_WIN32
343                 err = mkdir (tmp);
344 #else
345                 err = mkdir (tmp, 0777);
346 #endif
347                 if (err) {
348                         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT failed: %s", g_strerror (errno));
349                         g_free (tmp);
350                         return;
351                 }
352         }
353         g_free (tmp);
354 }
355
356 /*
357  * load_aot_module_from_cache:
358  *
359  *  Experimental code to AOT compile loaded assemblies on demand. 
360  *
361  * FIXME: 
362  * - Add environment variable MONO_AOT_CACHE_OPTIONS
363  * - Add options for controlling the cache size
364  * - Handle full cache by deleting old assemblies lru style
365  * - Add options for excluding assemblies during development
366  * - Maybe add a threshold after an assembly is AOT compiled
367  * - invoking a new mono process is a security risk
368  */
369 static GModule*
370 load_aot_module_from_cache (MonoAssembly *assembly, char **aot_name)
371 {
372         char *fname, *cmd, *tmp2;
373         const char *home;
374         GModule *module;
375         gboolean res;
376         gchar *out, *err;
377
378         *aot_name = NULL;
379
380         if (assembly->image->dynamic)
381                 return NULL;
382
383         create_cache_structure ();
384
385         home = g_get_home_dir ();
386
387         tmp2 = g_strdup_printf ("%s-%s%s", assembly->image->assembly_name, assembly->image->guid, SHARED_EXT);
388         fname = g_build_filename (home, ".mono", "aot-cache", tmp2, NULL);
389         *aot_name = fname;
390         g_free (tmp2);
391
392         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT trying to load from cache: '%s'.", fname);
393         module = g_module_open (fname, G_MODULE_BIND_LAZY);     
394
395         if (!module) {
396                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT not found.");
397
398                 mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT precompiling assembly '%s'... ", assembly->image->name);
399
400                 /* FIXME: security */
401                 cmd = g_strdup_printf ("mono -O=all --aot=outfile=%s %s", fname, assembly->image->name);
402
403                 res = g_spawn_command_line_sync (cmd, &out, &err, NULL, NULL);
404                 g_free (cmd);
405                 if (!res) {
406                         mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT failed.");
407                         return NULL;
408                 }
409
410                 mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT succeeded.");
411
412                 module = g_module_open (fname, G_MODULE_BIND_LAZY);     
413         }
414
415         return module;
416 }
417
418 static void
419 load_aot_module (MonoAssembly *assembly, gpointer user_data)
420 {
421         char *aot_name;
422         MonoAotModule *info;
423         gboolean usable = TRUE;
424         char *saved_guid = NULL;
425         char *aot_version = NULL;
426         char *opt_flags = NULL;
427
428 #ifdef MONO_ARCH_HAVE_PIC_AOT
429         gpointer *got_addr = NULL;
430         gpointer *got = NULL;
431         guint32 *got_size_ptr = NULL;
432 #endif
433
434         if (mono_compile_aot)
435                 return;
436                                                         
437         if (use_aot_cache)
438                 assembly->aot_module = load_aot_module_from_cache (assembly, &aot_name);
439         else {
440                 aot_name = g_strdup_printf ("%s%s", assembly->image->name, SHARED_EXT);
441
442                 assembly->aot_module = g_module_open (aot_name, G_MODULE_BIND_LAZY);
443
444                 if (!assembly->aot_module) {
445                         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT failed to load AOT module %s: %s\n", aot_name, g_module_error ());
446                 }
447         }
448
449         if (!assembly->aot_module) {
450                 g_free (aot_name);
451                 return;
452         }
453
454         g_module_symbol (assembly->aot_module, "mono_assembly_guid", (gpointer *) &saved_guid);
455         g_module_symbol (assembly->aot_module, "mono_aot_version", (gpointer *) &aot_version);
456         g_module_symbol (assembly->aot_module, "mono_aot_opt_flags", (gpointer *)&opt_flags);
457
458         if (!aot_version || strcmp (aot_version, MONO_AOT_FILE_VERSION)) {
459                 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);
460                 usable = FALSE;
461         }
462         else {
463                 if (!saved_guid || strcmp (assembly->image->guid, saved_guid)) {
464                         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT module %s is out of date.\n", aot_name);
465                         usable = FALSE;
466                 }
467         }
468
469         if (!usable) {
470                 g_free (aot_name);
471                 g_module_close (assembly->aot_module);
472                 assembly->aot_module = NULL;
473                 return;
474         }
475
476 #ifdef MONO_ARCH_HAVE_PIC_AOT
477         g_module_symbol (assembly->aot_module, "got_addr", (gpointer *)&got_addr);
478         g_assert (got_addr);
479         got = (gpointer*)*got_addr;
480         g_assert (got);
481         g_module_symbol (assembly->aot_module, "got_size", (gpointer *)&got_size_ptr);
482         g_assert (got_size_ptr);
483 #endif
484
485         info = g_new0 (MonoAotModule, 1);
486         info->aot_name = aot_name;
487 #ifdef MONO_ARCH_HAVE_PIC_AOT
488         info->got = got;
489         info->got_size = *got_size_ptr;
490         info->got [0] = assembly->image;
491 #endif
492         sscanf (opt_flags, "%d", &info->opts);
493
494         /* Read image table */
495         {
496                 guint32 table_len, i;
497                 char *table = NULL;
498
499                 g_module_symbol (assembly->aot_module, "mono_image_table", (gpointer *)&table);
500                 g_assert (table);
501
502                 table_len = *(guint32*)table;
503                 table += sizeof (guint32);
504                 info->image_table = g_new0 (MonoImage*, table_len);
505                 info->image_names = g_new0 (MonoAssemblyName, table_len);
506                 info->image_guids = g_new0 (char*, table_len);
507                 for (i = 0; i < table_len; ++i) {
508                         MonoAssemblyName *aname = &(info->image_names [i]);
509
510                         aname->name = g_strdup (table);
511                         table += strlen (table) + 1;
512                         info->image_guids [i] = g_strdup (table);
513                         table += strlen (table) + 1;
514                         if (table [0] != 0)
515                                 aname->culture = g_strdup (table);
516                         table += strlen (table) + 1;
517                         memcpy (aname->public_key_token, table, strlen (table) + 1);
518                         table += strlen (table) + 1;                    
519
520                         table = ALIGN_PTR_TO (table, 8);
521                         aname->flags = *(guint32*)table;
522                         table += 4;
523                         aname->major = *(guint32*)table;
524                         table += 4;
525                         aname->minor = *(guint32*)table;
526                         table += 4;
527                         aname->build = *(guint32*)table;
528                         table += 4;
529                         aname->revision = *(guint32*)table;
530                         table += 4;
531                 }
532         }
533
534         /* Read icall table */
535         {
536                 guint32 table_len, i;
537                 char *table = NULL;
538
539                 g_module_symbol (assembly->aot_module, "mono_icall_table", (gpointer *)&table);
540                 g_assert (table);
541
542                 table_len = *(guint32*)table;
543                 table += sizeof (guint32);
544                 info->icall_table = g_new0 (char*, table_len);
545                 for (i = 0; i < table_len; ++i) {
546                         info->icall_table [i] = table;
547                         table += strlen (table) + 1;
548                 }
549         }
550
551         /* Read method and method_info tables */
552         g_module_symbol (assembly->aot_module, "method_offsets", (gpointer*)&info->code_offsets);
553         g_module_symbol (assembly->aot_module, "methods", (gpointer*)&info->code);
554         g_module_symbol (assembly->aot_module, "methods_end", (gpointer*)&info->code_end);
555         g_module_symbol (assembly->aot_module, "method_info_offsets", (gpointer*)&info->method_info_offsets);
556         g_module_symbol (assembly->aot_module, "method_infos", (gpointer*)&info->method_infos);
557         g_module_symbol (assembly->aot_module, "ex_info_offsets", (gpointer*)&info->ex_info_offsets);
558         g_module_symbol (assembly->aot_module, "ex_infos", (gpointer*)&info->ex_infos);
559         g_module_symbol (assembly->aot_module, "method_order", (gpointer*)&info->method_order);
560         g_module_symbol (assembly->aot_module, "method_order_end", (gpointer*)&info->method_order_end);
561         g_module_symbol (assembly->aot_module, "class_infos", (gpointer*)&info->class_infos);
562         g_module_symbol (assembly->aot_module, "class_info_offsets", (gpointer*)&info->class_info_offsets);
563         g_module_symbol (assembly->aot_module, "mem_end", (gpointer*)&info->mem_end);
564
565         info->mem_begin = info->code;
566
567         if (make_unreadable) {
568 #ifndef PLATFORM_WIN32
569                 guint8 *addr;
570                 guint8 *page_start;
571                 int pages, err, len;
572
573                 addr = info->mem_begin;
574                 len = info->mem_end - info->mem_begin;
575
576                 /* Round down in both directions to avoid modifying data which is not ours */
577                 page_start = (guint8 *) (((gssize) (addr)) & ~ (PAGESIZE - 1)) + PAGESIZE;
578                 pages = ((addr + len - page_start + PAGESIZE - 1) / PAGESIZE) - 1;
579                 err = mprotect (page_start, pages * PAGESIZE, 0);
580                 g_assert (err == 0);
581 #endif
582         }
583
584         mono_aot_lock ();
585         g_hash_table_insert (aot_modules, assembly, info);
586         mono_aot_unlock ();
587
588         mono_jit_info_add_aot_module (assembly->image, info->code, info->code_end);
589
590         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT loaded AOT Module for %s.\n", assembly->image->name);
591 }
592
593 void
594 mono_aot_init (void)
595 {
596         InitializeCriticalSection (&aot_mutex);
597         aot_modules = g_hash_table_new (NULL, NULL);
598
599         mono_install_assembly_load_hook (load_aot_module, NULL);
600
601         if (getenv ("MONO_LASTAOT"))
602                 mono_last_aot_method = atoi (getenv ("MONO_LASTAOT"));
603         if (getenv ("MONO_AOT_CACHE"))
604                 use_aot_cache = TRUE;
605 }
606
607 static gboolean
608 decode_cached_class_info (MonoAotModule *module, MonoCachedClassInfo *info, guint8 *buf, guint8 **endbuf)
609 {
610         guint32 flags;
611
612         info->vtable_size = decode_value (buf, &buf);
613         flags = decode_value (buf, &buf);
614         info->ghcimpl = (flags >> 0) & 0x1;
615         info->has_finalize = (flags >> 1) & 0x1;
616         info->has_cctor = (flags >> 2) & 0x1;
617         info->has_nested_classes = (flags >> 3) & 0x1;
618         info->blittable = (flags >> 4) & 0x1;
619         info->has_references = (flags >> 5) & 0x1;
620         info->has_static_refs = (flags >> 6) & 0x1;
621         info->no_special_static_fields = (flags >> 7) & 0x1;
622
623         if (info->has_cctor) {
624                 MonoImage *cctor_image = decode_method_ref (module, &info->cctor_token, buf, &buf);
625                 if (!cctor_image)
626                         return FALSE;
627         }
628         if (info->has_finalize) {
629                 info->finalize_image = decode_method_ref (module, &info->finalize_token, buf, &buf);
630                 if (!info->finalize_image)
631                         return FALSE;
632         }
633
634         info->instance_size = decode_value (buf, &buf);
635         info->class_size = decode_value (buf, &buf);
636         info->packing_size = decode_value (buf, &buf);
637         info->min_align = decode_value (buf, &buf);
638
639         *endbuf = buf;
640
641         return TRUE;
642 }       
643
644 gboolean
645 mono_aot_init_vtable (MonoVTable *vtable)
646 {
647         int i;
648         MonoAotModule *aot_module;
649         MonoClass *klass = vtable->klass;
650         guint8 *info, *p;
651         MonoCachedClassInfo class_info;
652         gboolean err;
653
654         if (MONO_CLASS_IS_INTERFACE (klass) || klass->rank || !klass->image->assembly->aot_module)
655                 return FALSE;
656
657         mono_aot_lock ();
658
659         aot_module = (MonoAotModule*) g_hash_table_lookup (aot_modules, klass->image->assembly);
660         if (!aot_module) {
661                 mono_aot_unlock ();
662                 return FALSE;
663         }
664
665         info = &aot_module->class_infos [aot_module->class_info_offsets [mono_metadata_token_index (klass->type_token) - 1]];
666         p = info;
667
668         err = decode_cached_class_info (aot_module, &class_info, p, &p);
669         if (!err) {
670                 mono_aot_unlock ();
671                 return FALSE;
672         }
673
674         //printf ("VT0: %s.%s %d\n", klass->name_space, klass->name, vtable_size);
675         for (i = 0; i < class_info.vtable_size; ++i) {
676                 guint32 image_index, token, value;
677                 MonoImage *image;
678 #ifndef MONO_ARCH_HAVE_CREATE_TRAMPOLINE_FROM_TOKEN
679                 MonoMethod *m;
680 #endif
681
682                 vtable->vtable [i] = 0;
683
684                 value = decode_value (p, &p);
685                 if (!value)
686                         continue;
687
688                 image_index = value >> 24;
689                 token = MONO_TOKEN_METHOD_DEF | (value & 0xffffff);
690
691                 image = load_image (aot_module, image_index);
692                 if (!image) {
693                         mono_aot_unlock ();
694                         return FALSE;
695                 }
696
697 #ifdef MONO_ARCH_HAVE_CREATE_TRAMPOLINE_FROM_TOKEN
698                 vtable->vtable [i] = mono_create_jit_trampoline_from_token (image, token);
699 #else
700                 m = mono_get_method (image, token, NULL);
701                 g_assert (m);
702
703                 //printf ("M: %d %p %s\n", i, &(vtable->vtable [i]), mono_method_full_name (m, TRUE));
704                 vtable->vtable [i] = mono_create_jit_trampoline (m);
705 #endif
706         }
707
708         mono_aot_unlock ();
709
710         return TRUE;
711 }
712
713 gboolean
714 mono_aot_get_cached_class_info (MonoClass *klass, MonoCachedClassInfo *res)
715 {
716         MonoAotModule *aot_module;
717         guint8 *p;
718         gboolean err;
719
720         if (klass->rank || !klass->image->assembly->aot_module)
721                 return FALSE;
722
723         mono_aot_lock ();
724
725         aot_module = (MonoAotModule*) g_hash_table_lookup (aot_modules, klass->image->assembly);
726         if (!aot_module) {
727                 mono_aot_unlock ();
728                 return FALSE;
729         }
730
731         p = (guint8*)&aot_module->class_infos [aot_module->class_info_offsets [mono_metadata_token_index (klass->type_token) - 1]];
732
733         err = decode_cached_class_info (aot_module, res, p, &p);
734         if (!err) {
735                 mono_aot_unlock ();
736                 return FALSE;
737         }
738
739         mono_aot_unlock ();
740
741         return TRUE;
742 }
743
744 static MonoJitInfo*
745 decode_exception_debug_info (MonoAotModule *aot_module, MonoDomain *domain, 
746                                                          MonoMethod *method, guint8* ex_info, guint8 *code)
747 {
748         int i, buf_len;
749         MonoJitInfo *jinfo;
750         guint code_len, used_int_regs;
751         guint8 *p;
752         MonoMethodHeader *header;
753
754         header = mono_method_get_header (method);
755
756         /* Load the method info from the AOT file */
757
758         p = ex_info;
759         code_len = decode_value (p, &p);
760         used_int_regs = decode_value (p, &p);
761
762         /* Exception table */
763         if (header->num_clauses) {
764                 jinfo = 
765                         mono_mempool_alloc0 (domain->mp, sizeof (MonoJitInfo) + (sizeof (MonoJitExceptionInfo) * header->num_clauses));
766                 jinfo->num_clauses = header->num_clauses;
767
768                 for (i = 0; i < header->num_clauses; ++i) {
769                         MonoExceptionClause *ec = &header->clauses [i];                         
770                         MonoJitExceptionInfo *ei = &jinfo->clauses [i];
771
772                         ei->flags = ec->flags;
773                         ei->exvar_offset = decode_value (p, &p);
774
775                         if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)
776                                 ei->data.filter = code + decode_value (p, &p);
777                         else
778                                 ei->data.catch_class = ec->data.catch_class;
779
780                         ei->try_start = code + decode_value (p, &p);
781                         ei->try_end = code + decode_value (p, &p);
782                         ei->handler_start = code + decode_value (p, &p);
783                 }
784         }
785         else
786                 jinfo = mono_mempool_alloc0 (domain->mp, sizeof (MonoJitInfo));
787
788         jinfo->code_size = code_len;
789         jinfo->used_regs = used_int_regs;
790         jinfo->method = method;
791         jinfo->code_start = code;
792 #ifdef MONO_ARCH_HAVE_PIC_AOT
793         jinfo->domain_neutral = 0;
794 #else
795         jinfo->domain_neutral = (aot_module->opts & MONO_OPT_SHARED) != 0;
796 #endif
797
798         /* Load debug info */
799         buf_len = decode_value (p, &p);
800         mono_debug_add_aot_method (domain, method, code, p, buf_len);
801         
802         return jinfo;
803 }
804
805 MonoJitInfo *
806 mono_aot_find_jit_info (MonoDomain *domain, MonoImage *image, gpointer addr)
807 {
808         MonoAssembly *ass = image->assembly;
809         GModule *module = ass->aot_module;
810         int pos, left, right, offset, offset1, offset2, last_offset, new_offset, page_index, method_index, table_len;
811         guint32 token;
812         MonoAotModule *aot_module;
813         MonoMethod *method;
814         MonoJitInfo *jinfo;
815         guint8 *code, *ex_info;
816         guint32 *table, *ptr;
817         gboolean found;
818
819         if (!module)
820                 return NULL;
821
822         aot_module = (MonoAotModule*) g_hash_table_lookup (aot_modules, ass);
823
824         if (domain != mono_get_root_domain ())
825                 /* FIXME: */
826                 return NULL;
827
828         offset = (guint8*)addr - aot_module->code;
829
830         /* First search through the index */
831         ptr = aot_module->method_order;
832         last_offset = 0;
833         page_index = 0;
834         found = FALSE;
835
836         if (*ptr == 0xffffff)
837                 return NULL;
838         ptr ++;
839
840         while (*ptr != 0xffffff) {
841                 guint32 method_index = ptr [0];
842                 new_offset = aot_module->code_offsets [method_index];
843
844                 if (offset >= last_offset && offset < new_offset) {
845                         found = TRUE;
846                         break;
847                 }
848
849                 ptr ++;
850                 last_offset = new_offset;
851                 page_index ++;
852         }
853
854         /* Skip rest of index */
855         while (*ptr != 0xffffff)
856                 ptr ++;
857         ptr ++;
858
859         table = ptr;
860         table_len = aot_module->method_order_end - table;
861
862         g_assert (table <= aot_module->method_order_end);
863
864         if (found) {
865                 left = (page_index * 1024);
866                 right = left + 1024;
867
868                 if (right > table_len)
869                         right = table_len;
870
871                 offset1 = aot_module->code_offsets [table [left]];
872                 g_assert (offset1 <= offset);
873
874                 //printf ("Found in index: 0x%x 0x%x 0x%x\n", offset, last_offset, new_offset);
875         }
876         else {
877                 //printf ("Not found in index: 0x%x\n", offset);
878                 left = 0;
879                 right = table_len;
880         }
881
882         /* Binary search inside the method_order table to find the method */
883         while (TRUE) {
884                 pos = (left + right) / 2;
885
886                 g_assert (table + pos <= aot_module->method_order_end);
887
888                 //printf ("Pos: %5d < %5d < %5d Offset: 0x%05x < 0x%05x < 0x%05x\n", left, pos, right, aot_module->code_offsets [table [left]], offset, aot_module->code_offsets [table [right]]);
889
890                 offset1 = aot_module->code_offsets [table [pos]];
891                 if (table + pos + 1 >= aot_module->method_order_end)
892                         offset2 = aot_module->code_end - aot_module->code;
893                 else
894                         offset2 = aot_module->code_offsets [table [pos + 1]];
895
896                 if (offset < offset1)
897                         right = pos;
898                 else if (offset >= offset2)
899                         left = pos + 1;
900                 else
901                         break;
902         }
903
904         method_index = table [pos];
905
906         token = mono_metadata_make_token (MONO_TABLE_METHOD, method_index + 1);
907         method = mono_get_method (image, token, NULL);
908
909         /* FIXME: */
910         g_assert (method);
911
912         //printf ("F: %s\n", mono_method_full_name (method, TRUE));
913
914         code = &aot_module->code [aot_module->code_offsets [method_index]];
915         ex_info = &aot_module->ex_infos [aot_module->ex_info_offsets [method_index]];
916
917         jinfo = decode_exception_debug_info (aot_module, domain, method, ex_info, code);
918
919         g_assert ((guint8*)addr >= (guint8*)jinfo->code_start);
920         g_assert ((guint8*)addr < (guint8*)jinfo->code_start + jinfo->code_size);
921
922         /* Add it to the normal JitInfo tables */
923         mono_jit_info_table_add (domain, jinfo);
924         
925         return jinfo;
926 }
927
928 static MonoJumpInfo*
929 load_patch_info (MonoAotModule *aot_module, MonoMemPool *mp, int n_patches, 
930                                  guint32 got_index, guint32 **got_slots, 
931                                  guint8 *buf, guint8 **endbuf)
932 {
933         MonoJumpInfo *patches;
934         MonoJumpInfo *patch_info = NULL;
935         MonoImage *image;
936         gpointer *table;
937         int i, pindex;
938         guint32 last_offset;
939         guint8 *p;
940
941         p = buf;
942
943         /* First load the type + offset table */
944         last_offset = 0;
945         patches = mono_mempool_alloc (mp, sizeof (MonoJumpInfo) * n_patches);
946
947         for (pindex = 0; pindex < n_patches; ++pindex) {                
948                 MonoJumpInfo *ji = &patches [pindex];
949
950 #if defined(MONO_ARCH_HAVE_PIC_AOT)
951                 ji->type = *p;
952                 p ++;
953 #else
954                 guint8 b1, b2;
955
956                 b1 = *(guint8*)p;
957                 b2 = *((guint8*)p + 1);
958                 p += 2;
959
960                 ji->type = b1 >> 2;
961
962                 if (((b1 & (1 + 2)) == 3) && (b2 == 255))
963                         ji->ip.i = decode_value (p, &p);
964                 else
965                         ji->ip.i = (((guint32)(b1 & (1 + 2))) << 8) + b2;
966
967                 ji->ip.i += last_offset;
968                 last_offset = ji->ip.i;
969 #endif
970                 //printf ("T: %d O: %d.\n", ji->type, ji->ip.i);
971                 ji->next = patch_info;
972                 patch_info = ji;
973         }
974
975         *got_slots = g_malloc (sizeof (guint32) * n_patches);
976         memset (*got_slots, 0xff, sizeof (guint32) * n_patches);
977
978         /* Then load the other data */
979         for (pindex = 0; pindex < n_patches; ++pindex) {
980                 MonoJumpInfo *ji = &patches [pindex];
981
982                 switch (ji->type) {
983                 case MONO_PATCH_INFO_CLASS:
984                 case MONO_PATCH_INFO_IID:
985                 case MONO_PATCH_INFO_VTABLE:
986                 case MONO_PATCH_INFO_CLASS_INIT:
987                         ji->data.klass = decode_klass_info (aot_module, p, &p);
988                         if (!ji->data.klass)
989                                 goto cleanup;
990                         break;
991                 case MONO_PATCH_INFO_IMAGE:
992                         ji->data.image = load_image (aot_module, decode_value (p, &p));
993                         if (!ji->data.image)
994                                 goto cleanup;
995                         break;
996                 case MONO_PATCH_INFO_METHOD:
997                 case MONO_PATCH_INFO_METHODCONST:
998                 case MONO_PATCH_INFO_METHOD_JUMP: {
999                         guint32 image_index, token, value;
1000
1001                         value = decode_value (p, &p);
1002                         image_index = value >> 24;
1003                         token = MONO_TOKEN_METHOD_DEF | (value & 0xffffff);
1004
1005                         image = load_image (aot_module, image_index);
1006                         if (!image)
1007                                 goto cleanup;
1008
1009 #ifdef MONO_ARCH_HAVE_CREATE_TRAMPOLINE_FROM_TOKEN
1010                         if (ji->type == MONO_PATCH_INFO_METHOD) {
1011                                 ji->data.target = mono_create_jit_trampoline_from_token (image, token);
1012                                 ji->type = MONO_PATCH_INFO_ABS;
1013                         }
1014                         else {
1015                                 ji->data.method = mono_get_method (image, token, NULL);
1016                                 g_assert (ji->data.method);
1017                                 mono_class_init (ji->data.method->klass);
1018                         }
1019 #else
1020                         ji->data.method = mono_get_method (image, token, NULL);
1021                         g_assert (ji->data.method);
1022                         mono_class_init (ji->data.method->klass);
1023 #endif
1024
1025                         break;
1026                 }
1027                 case MONO_PATCH_INFO_WRAPPER: {
1028                         guint32 wrapper_type;
1029
1030                         wrapper_type = decode_value (p, &p);
1031
1032                         switch (wrapper_type) {
1033                         case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK: {
1034                                 guint32 image_index, token, value;
1035
1036                                 value = decode_value (p, &p);
1037                                 image_index = value >> 24;
1038                                 token = MONO_TOKEN_METHOD_DEF | (value & 0xffffff);
1039
1040                                 image = load_image (aot_module, image_index);
1041                                 if (!image)
1042                                         goto cleanup;
1043                                 ji->data.method = mono_get_method (image, token, NULL);
1044                                 g_assert (ji->data.method);
1045                                 mono_class_init (ji->data.method->klass);
1046
1047                                 ji->type = MONO_PATCH_INFO_METHOD;
1048                                 ji->data.method = mono_marshal_get_remoting_invoke_with_check (ji->data.method);
1049                                 break;
1050                         }
1051                         case MONO_WRAPPER_PROXY_ISINST: {
1052                                 MonoClass *klass = decode_klass_info (aot_module, p, &p);
1053                                 if (!klass)
1054                                         goto cleanup;
1055                                 ji->type = MONO_PATCH_INFO_METHOD;
1056                                 ji->data.method = mono_marshal_get_proxy_cancast (klass);
1057                                 break;
1058                         }
1059                         case MONO_WRAPPER_LDFLD:
1060                         case MONO_WRAPPER_LDFLDA:
1061                         case MONO_WRAPPER_STFLD:
1062                         case MONO_WRAPPER_LDFLD_REMOTE:
1063                         case MONO_WRAPPER_STFLD_REMOTE:
1064                         case MONO_WRAPPER_ISINST: {
1065                                 MonoClass *klass = decode_klass_info (aot_module, p, &p);
1066                                 if (!klass)
1067                                         goto cleanup;
1068                                 ji->type = MONO_PATCH_INFO_METHOD;
1069                                 if (wrapper_type == MONO_WRAPPER_LDFLD)
1070                                         ji->data.method = mono_marshal_get_ldfld_wrapper (&klass->byval_arg);
1071                                 else if (wrapper_type == MONO_WRAPPER_LDFLDA)
1072                                         ji->data.method = mono_marshal_get_ldflda_wrapper (&klass->byval_arg);
1073                                 else if (wrapper_type == MONO_WRAPPER_STFLD)
1074                                         ji->data.method = mono_marshal_get_stfld_wrapper (&klass->byval_arg);
1075                                 else if (wrapper_type == MONO_WRAPPER_LDFLD_REMOTE)
1076                                         ji->data.method = mono_marshal_get_ldfld_remote_wrapper (klass);
1077                                 else if (wrapper_type == MONO_WRAPPER_STFLD_REMOTE)
1078                                         ji->data.method = mono_marshal_get_stfld_remote_wrapper (klass);
1079                                 else if (wrapper_type == MONO_WRAPPER_ISINST)
1080                                         ji->data.method = mono_marshal_get_isinst (klass);
1081                                 else
1082                                         g_assert_not_reached ();
1083                                 break;
1084                         }
1085                         case MONO_WRAPPER_STELEMREF:
1086                                 ji->type = MONO_PATCH_INFO_METHOD;
1087                                 ji->data.method = mono_marshal_get_stelemref ();
1088                                 break;
1089                         default:
1090                                 g_assert_not_reached ();
1091                         }
1092                         break;
1093                 }
1094                 case MONO_PATCH_INFO_FIELD:
1095                 case MONO_PATCH_INFO_SFLDA:
1096                         ji->data.field = decode_field_info (aot_module, p, &p);
1097                         if (!ji->data.field)
1098                                 goto cleanup;
1099                         break;
1100                 case MONO_PATCH_INFO_INTERNAL_METHOD: {
1101                         guint32 icall_index = decode_value (p, &p);
1102
1103                         ji->data.name = aot_module->icall_table [icall_index];
1104                         g_assert (ji->data.name);
1105
1106 #if MONO_ARCH_HAVE_PIC_AOT
1107                         /* GOT entries for icalls are at the start of the got */
1108                         (*got_slots) [pindex] = ICALL_GOT_SLOTS_START_INDEX + icall_index;
1109 #endif
1110                         break;
1111                 }
1112                 case MONO_PATCH_INFO_SWITCH:
1113                         ji->data.table = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoBBTable));
1114                         ji->data.table->table_size = decode_value (p, &p);
1115                         table = g_new (gpointer, ji->data.table->table_size);
1116                         ji->data.table->table = (MonoBasicBlock**)table;
1117                         for (i = 0; i < ji->data.table->table_size; i++)
1118                                 table [i] = (gpointer)(gssize)decode_value (p, &p);
1119                         break;
1120                 case MONO_PATCH_INFO_R4: {
1121                         guint32 val;
1122
1123                         ji->data.target = mono_mempool_alloc0 (mp, sizeof (float));
1124                         val = decode_value (p, &p);
1125                         *(float*)ji->data.target = *(float*)&val;
1126                         break;
1127                 }
1128                 case MONO_PATCH_INFO_R8: {
1129                         guint32 val [2];
1130
1131                         ji->data.target = mono_mempool_alloc0 (mp, sizeof (double));
1132
1133                         val [0] = decode_value (p, &p);
1134                         val [1] = decode_value (p, &p);
1135                         *(double*)ji->data.target = *(double*)val;
1136                         break;
1137                 }
1138                 case MONO_PATCH_INFO_LDSTR:
1139                         image = load_image (aot_module, decode_value (p, &p));
1140                         if (!image)
1141                                 goto cleanup;
1142                         ji->data.token = mono_jump_info_token_new (mp, image, MONO_TOKEN_STRING + decode_value (p, &p));
1143                         break;
1144                 case MONO_PATCH_INFO_DECLSEC:
1145                 case MONO_PATCH_INFO_LDTOKEN:
1146                 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1147                         image = load_image (aot_module, decode_value (p, &p));
1148                         if (!image)
1149                                 goto cleanup;
1150                         ji->data.token = mono_jump_info_token_new (mp, image, decode_value (p, &p));
1151                         break;
1152                 case MONO_PATCH_INFO_EXC_NAME:
1153                         ji->data.klass = decode_klass_info (aot_module, p, &p);
1154                         if (!ji->data.klass)
1155                                 goto cleanup;
1156                         ji->data.name = ji->data.klass->name;
1157                         break;
1158                 case MONO_PATCH_INFO_METHOD_REL:
1159                         ji->data.offset = decode_value (p, &p);
1160                         break;
1161                 default:
1162                         g_warning ("unhandled type %d", ji->type);
1163                         g_assert_not_reached ();
1164                 }
1165
1166 #if MONO_ARCH_HAVE_PIC_AOT
1167                 if ((*got_slots) [pindex] == 0xffffffff)
1168                         (*got_slots) [pindex] = got_index ++;
1169 #endif
1170         }
1171
1172         *endbuf = p;
1173         return patches;
1174
1175  cleanup:
1176         g_free (*got_slots);
1177         *got_slots = NULL;
1178
1179         return NULL;
1180 }
1181  
1182 static MonoJitInfo *
1183 mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method)
1184 {
1185         MonoClass *klass = method->klass;
1186         MonoAssembly *ass = klass->image->assembly;
1187         GModule *module = ass->aot_module;
1188         guint8 *code, *info, *ex_info;
1189         MonoAotModule *aot_module;
1190
1191         if (!module)
1192                 return NULL;
1193
1194         if (!method->token)
1195                 return NULL;
1196
1197         if (mono_profiler_get_events () & MONO_PROFILE_ENTER_LEAVE)
1198                 return NULL;
1199
1200         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
1201                 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
1202                 (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
1203                 (method->flags & METHOD_ATTRIBUTE_ABSTRACT))
1204                 return NULL;
1205         
1206         aot_module = (MonoAotModule*) g_hash_table_lookup (aot_modules, ass);
1207
1208         g_assert (klass->inited);
1209
1210         if ((domain != mono_get_root_domain ()) && (!(aot_module->opts & MONO_OPT_SHARED)))
1211                 /* Non shared AOT code can't be used in other appdomains */
1212                 return NULL;
1213
1214         if (aot_module->out_of_date)
1215                 return NULL;
1216
1217         if (aot_module->code_offsets [mono_metadata_token_index (method->token) - 1] == 0xffffffff) {
1218                 if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT)) {
1219                         char *full_name = mono_method_full_name (method, TRUE);
1220                         mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT NOT FOUND: %s.\n", full_name);
1221                         g_free (full_name);
1222                 }
1223                 return NULL;
1224         }
1225
1226         code = &aot_module->code [aot_module->code_offsets [mono_metadata_token_index (method->token) - 1]];
1227         info = &aot_module->method_infos [aot_module->method_info_offsets [mono_metadata_token_index (method->token) - 1]];
1228         ex_info = &aot_module->ex_infos [aot_module->ex_info_offsets [mono_metadata_token_index (method->token) - 1]];
1229
1230         if (mono_last_aot_method != -1) {
1231                 if (mono_jit_stats.methods_aot > mono_last_aot_method)
1232                                 return NULL;
1233                 else
1234                         if (mono_jit_stats.methods_aot == mono_last_aot_method)
1235                                 printf ("LAST AOT METHOD: %s.%s.%s.\n", klass->name_space, klass->name, method->name);
1236         }
1237
1238         return mono_aot_load_method (domain, aot_module, method, code, info, ex_info);
1239 }
1240
1241 static MonoJitInfo*
1242 mono_aot_load_method (MonoDomain *domain, MonoAotModule *aot_module, MonoMethod *method, guint8 *code, guint8 *info, guint8* ex_info)
1243 {
1244         MonoClass *klass = method->klass;
1245         MonoJumpInfo *patch_info = NULL;
1246         MonoJitInfo *jinfo;
1247         MonoMemPool *mp;
1248         int i, pindex, got_index = 0, n_patches, used_strings;
1249         gboolean non_got_patches, keep_patches = TRUE;
1250         guint8 *p;
1251
1252         jinfo = decode_exception_debug_info (aot_module, domain, method, ex_info, code);
1253
1254         p = info;
1255         decode_klass_info (aot_module, p, &p);
1256
1257         if (!use_loaded_code) {
1258                 guint8 *code2;
1259                 code2 = mono_code_manager_reserve (domain->code_mp, jinfo->code_size);
1260                 memcpy (code2, code, jinfo->code_size);
1261                 mono_arch_flush_icache (code2, jinfo->code_size);
1262                 code = code2;
1263         }
1264
1265         if (aot_module->opts & MONO_OPT_SHARED)
1266                 used_strings = decode_value (p, &p);
1267         else
1268                 used_strings = 0;
1269
1270         for (i = 0; i < used_strings; i++) {
1271                 guint token = decode_value (p, &p);
1272                 mono_ldstr (mono_get_root_domain (), klass->image, mono_metadata_token_index (token));
1273         }
1274
1275         if (aot_module->opts & MONO_OPT_SHARED) 
1276                 keep_patches = FALSE;
1277
1278 #ifdef MONO_ARCH_HAVE_PIC_AOT
1279         got_index = decode_value (p, &p);
1280         keep_patches = FALSE;
1281 #endif
1282
1283         n_patches = decode_value (p, &p);
1284
1285         if (n_patches) {
1286                 MonoJumpInfo *patches;
1287                 guint32 *got_slots;
1288
1289                 if (keep_patches)
1290                         mp = domain->mp;
1291                 else
1292                         mp = mono_mempool_new ();
1293
1294                 patches = load_patch_info (aot_module, mp, n_patches, got_index, &got_slots, p, &p);
1295                 if (patches == NULL)
1296                         goto cleanup;
1297
1298 #if MONO_ARCH_HAVE_PIC_AOT
1299                 /* Do this outside the lock to avoid deadlocks */
1300                 mono_aot_unlock ();
1301                 non_got_patches = FALSE;
1302                 for (pindex = 0; pindex < n_patches; ++pindex) {
1303                         MonoJumpInfo *ji = &patches [pindex];
1304
1305                         if (is_got_patch (ji->type)) {
1306                                 if (!aot_module->got [got_slots [pindex]])
1307                                         aot_module->got [got_slots [pindex]] = mono_resolve_patch_target (method, domain, code, ji, TRUE);
1308                                 ji->type = MONO_PATCH_INFO_NONE;
1309                         }
1310                         else
1311                                 non_got_patches = TRUE;
1312                 }
1313                 if (non_got_patches) {
1314                         mono_arch_flush_icache (code, jinfo->code_size);
1315                         make_writable (code, jinfo->code_size);
1316                         mono_arch_patch_code (method, domain, code, patch_info, TRUE);
1317                 }
1318                 mono_aot_lock ();
1319 #else
1320                 if (use_loaded_code)
1321                         /* disable write protection */
1322                         make_writable (code, jinfo->code_size);
1323
1324                 /* Do this outside the lock to avoid deadlocks */
1325                 mono_aot_unlock ();
1326                 mono_arch_patch_code (method, domain, code, patch_info, TRUE);
1327                 mono_aot_lock ();
1328 #endif
1329                 g_free (got_slots);
1330
1331                 if (!keep_patches)
1332                         mono_mempool_destroy (mp);
1333         }
1334
1335         mono_jit_stats.methods_aot++;
1336
1337         if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT)) {
1338                 char *full_name = mono_method_full_name (method, TRUE);
1339                 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT FOUND AOT compiled code for %s %p - %p %p\n", full_name, code, code + jinfo->code_size, info);
1340                 g_free (full_name);
1341         }
1342
1343         return jinfo;
1344
1345  cleanup:
1346         /* FIXME: The space in domain->mp is wasted */  
1347         if (aot_module->opts & MONO_OPT_SHARED)
1348                 /* No need to cache patches */
1349                 mono_mempool_destroy (mp);
1350
1351         return NULL;
1352 }
1353
1354 MonoJitInfo*
1355 mono_aot_get_method (MonoDomain *domain, MonoMethod *method)
1356 {
1357         MonoJitInfo *info;
1358
1359         mono_aot_lock ();
1360         info = mono_aot_get_method_inner (domain, method);
1361         mono_aot_unlock ();
1362
1363         /* Do this outside the lock */
1364         if (info) {
1365                 mono_jit_info_table_add (domain, info);
1366                 return info;
1367         }
1368         else
1369                 return NULL;
1370 }
1371
1372 static gpointer
1373 mono_aot_get_method_from_token_inner (MonoDomain *domain, MonoImage *image, guint32 token, MonoClass **klass)
1374 {
1375         MonoAssembly *ass = image->assembly;
1376         MonoMemPool *mp;
1377         int i, method_index, pindex, got_index, n_patches, used_strings;
1378         gboolean keep_patches = TRUE;
1379         guint8 *p;
1380         GModule *module = ass->aot_module;
1381         guint8 *code = NULL;
1382         guint8 *info;
1383         MonoAotModule *aot_module;
1384
1385         *klass = NULL;
1386
1387         if (!module)
1388                 return NULL;
1389
1390         if (mono_profiler_get_events () & MONO_PROFILE_ENTER_LEAVE)
1391                 return NULL;
1392
1393         aot_module = (MonoAotModule*) g_hash_table_lookup (aot_modules, ass);
1394
1395         if (domain != mono_get_root_domain ())
1396                 return NULL;
1397
1398         if (aot_module->out_of_date)
1399                 return NULL;
1400
1401         if (aot_module->code_offsets [mono_metadata_token_index (token) - 1] == 0xffffffff) {
1402                 return NULL;
1403         }
1404
1405         method_index = mono_metadata_token_index (token) - 1;
1406         code = &aot_module->code [aot_module->code_offsets [method_index]];
1407         info = &aot_module->method_infos [aot_module->method_info_offsets [method_index]];
1408
1409         if (mono_last_aot_method != -1) {
1410                 if (mono_jit_stats.methods_aot > mono_last_aot_method)
1411                                 return NULL;
1412                 else
1413                         if (mono_jit_stats.methods_aot == mono_last_aot_method) {
1414                                 MonoMethod *method = mono_get_method (image, token, NULL);
1415                                 printf ("LAST AOT METHOD: %s.%s.%s.\n", method->klass->name_space, method->klass->name, method->name);
1416                         }
1417         }
1418
1419         if (!aot_module->methods_loaded)
1420                 aot_module->methods_loaded = g_new0 (guint32, image->tables [MONO_TABLE_METHOD].rows + 1);
1421
1422         if ((aot_module->methods_loaded [method_index / 32] >> (method_index % 32)) & 0x1)
1423                 return code;
1424         else
1425                 aot_module->methods_loaded [method_index / 32] |= 1 << (method_index % 32);
1426
1427         p = info;
1428         *klass = decode_klass_info (aot_module, p, &p);
1429
1430         if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT)) {
1431                 MonoMethod *method = mono_get_method (image, token, NULL);
1432                 char *full_name = mono_method_full_name (method, TRUE);
1433                 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT FOUND AOT compiled code for %s %p %p\n", full_name, code, info);
1434                 g_free (full_name);
1435         }
1436
1437         if (aot_module->opts & MONO_OPT_SHARED)
1438                 used_strings = decode_value (p, &p);
1439         else
1440                 used_strings = 0;
1441
1442         for (i = 0; i < used_strings; i++) {
1443                 guint string_token = decode_value (p, &p);
1444                 mono_ldstr (mono_get_root_domain (), image, mono_metadata_token_index (string_token));
1445         }
1446
1447         if (aot_module->opts & MONO_OPT_SHARED) 
1448                 keep_patches = FALSE;
1449
1450         got_index = decode_value (p, &p);
1451         keep_patches = FALSE;
1452
1453         n_patches = decode_value (p, &p);
1454
1455         if (n_patches) {
1456                 MonoJumpInfo *patches;
1457                 guint32 *got_slots;
1458
1459                 if (keep_patches)
1460                         mp = domain->mp;
1461                 else
1462                         mp = mono_mempool_new ();
1463
1464                 patches = load_patch_info (aot_module, mp, n_patches, got_index, &got_slots, p, &p);
1465                 if (patches == NULL)
1466                         goto cleanup;
1467
1468                 /* Do this outside the lock to avoid deadlocks */
1469                 mono_aot_unlock ();
1470
1471                 for (pindex = 0; pindex < n_patches; ++pindex) {
1472                         MonoJumpInfo *ji = &patches [pindex];
1473
1474                         if (is_got_patch (ji->type)) {
1475                                 if (!aot_module->got [got_slots [pindex]])
1476                                         aot_module->got [got_slots [pindex]] = mono_resolve_patch_target (NULL, domain, code, ji, TRUE);
1477                                 ji->type = MONO_PATCH_INFO_NONE;
1478                         }
1479                 }
1480
1481                 mono_aot_lock ();
1482
1483                 g_free (got_slots);
1484
1485                 if (!keep_patches)
1486                         mono_mempool_destroy (mp);
1487         }
1488
1489         mono_jit_stats.methods_aot++;
1490
1491         return code;
1492
1493  cleanup:
1494         /* FIXME: The space in domain->mp is wasted */  
1495         if (aot_module->opts & MONO_OPT_SHARED)
1496                 /* No need to cache patches */
1497                 mono_mempool_destroy (mp);
1498
1499         return NULL;
1500 }
1501
1502 /**
1503  * Same as mono_aot_get_method, but we try to avoid loading any metadata from the
1504  * method.
1505  */
1506 gpointer
1507 mono_aot_get_method_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
1508 {
1509         gpointer res;   
1510         MonoClass *klass;
1511
1512         mono_aot_lock ();
1513         res = mono_aot_get_method_from_token_inner (domain, image, token, &klass);
1514         mono_aot_unlock ();
1515
1516         if (!res)
1517                 return NULL;
1518
1519         if (klass)
1520                 mono_runtime_class_init (mono_class_vtable (domain, klass));
1521
1522         return res;
1523 }
1524
1525 typedef struct {
1526         guint8 *addr;
1527         gboolean res;
1528 } IsGotEntryUserData;
1529
1530 static void
1531 check_is_got_entry (gpointer key, gpointer value, gpointer user_data)
1532 {
1533         IsGotEntryUserData *data = (IsGotEntryUserData*)user_data;
1534         MonoAotModule *aot_module = (MonoAotModule*)value;
1535
1536         if (aot_module->got && (data->addr >= (guint8*)(aot_module->got)) && (data->addr < (guint8*)(aot_module->got + aot_module->got_size)))
1537                 data->res = TRUE;
1538 }
1539
1540 gboolean
1541 mono_aot_is_got_entry (guint8 *code, guint8 *addr)
1542 {
1543         IsGotEntryUserData user_data;
1544
1545         if (!aot_modules)
1546                 return FALSE;
1547
1548         user_data.addr = addr;
1549         user_data.res = FALSE;
1550         mono_aot_lock ();
1551         g_hash_table_foreach (aot_modules, check_is_got_entry, &user_data);
1552         mono_aot_unlock ();
1553         
1554         return user_data.res;
1555 }
1556
1557 /*
1558  * mono_aot_set_make_unreadable:
1559  *
1560  *   Set whenever to make all mmaped memory unreadable. In conjuction with a
1561  * SIGSEGV handler, this is useful to find out which pages the runtime tries to read.
1562  */
1563 void
1564 mono_aot_set_make_unreadable (gboolean unreadable)
1565 {
1566         make_unreadable = unreadable;
1567 }
1568
1569 typedef struct {
1570         MonoAotModule *module;
1571         guint8 *ptr;
1572 } FindMapUserData;
1573
1574 static void
1575 find_map (gpointer key, gpointer value, gpointer user_data)
1576 {
1577         MonoAotModule *module = (MonoAotModule*)value;
1578         FindMapUserData *data = (FindMapUserData*)user_data;
1579
1580         if (!data->module)
1581                 if ((data->ptr >= module->mem_begin) && (data->ptr < module->mem_end))
1582                         data->module = module;
1583 }
1584
1585 static MonoAotModule*
1586 find_module_for_addr (void *ptr)
1587 {
1588         FindMapUserData data;
1589
1590         if (!make_unreadable)
1591                 return NULL;
1592
1593         data.module = NULL;
1594         data.ptr = (guint8*)ptr;
1595
1596         mono_aot_lock ();
1597         g_hash_table_foreach (aot_modules, (GHFunc)find_map, &data);
1598         mono_aot_unlock ();
1599
1600         return data.module;
1601 }
1602
1603 /*
1604  * mono_aot_is_pagefault:
1605  *
1606  *   Should be called from a SIGSEGV signal handler to find out whenever @ptr is
1607  * within memory allocated by this module.
1608  */
1609 gboolean
1610 mono_aot_is_pagefault (void *ptr)
1611 {
1612         if (!make_unreadable)
1613                 return FALSE;
1614
1615         return find_module_for_addr (ptr) != NULL;
1616 }
1617
1618 /*
1619  * mono_aot_handle_pagefault:
1620  *
1621  *   Handle a pagefault caused by an unreadable page by making it readable again.
1622  */
1623 void
1624 mono_aot_handle_pagefault (void *ptr)
1625 {
1626 #ifndef PLATFORM_WIN32
1627         guint8* start = (guint8*)ROUND_DOWN (((gssize)ptr), PAGESIZE);
1628         int res;
1629
1630         mono_aot_lock ();
1631         res = mprotect (start, PAGESIZE, PROT_READ|PROT_WRITE|PROT_EXEC);
1632         g_assert (res == 0);
1633
1634         n_pagefaults ++;
1635         mono_aot_unlock ();
1636 #endif
1637 }
1638
1639 /*
1640  * mono_aot_get_n_pagefaults:
1641  *
1642  *   Return the number of times handle_pagefault is called.
1643  */
1644 guint32
1645 mono_aot_get_n_pagefaults (void)
1646 {
1647         return n_pagefaults;
1648 }
1649
1650 /*****************************************************/
1651 /*                 AOT COMPILER                      */
1652 /*****************************************************/
1653
1654 static void
1655 emit_section_change (FILE *fp, const char *section_name, int subsection_index)
1656 {
1657 #if defined(PLATFORM_WIN32)
1658         fprintf (fp, ".section %s\n", section_name);
1659 #elif defined(sparc)
1660         /* For solaris as, GNU as should accept the same */
1661         fprintf (fp, ".section \"%s\"\n", section_name);
1662 #elif defined(__ppc__) && defined(__MACH__)
1663         /* This needs to be made more precise on mach. */
1664         fprintf (fp, "%s\n", subsection_index == 0 ? ".text" : ".data");
1665 #else
1666         fprintf (fp, "%s %d\n", section_name, subsection_index);
1667 #endif
1668 }
1669
1670 static void
1671 emit_symbol_type (FILE *fp, const char *name, gboolean func)
1672 {
1673         const char *stype;
1674
1675         if (func)
1676                 stype = "function";
1677         else
1678                 stype = "object";
1679
1680 #if defined(sparc)
1681         fprintf (fp, "\t.type %s,#%s\n", name, stype);
1682 #elif defined(PLATFORM_WIN32)
1683
1684 #elif !(defined(__ppc__) && defined(__MACH__))
1685         fprintf (fp, "\t.type %s,@%s\n", name, stype);
1686 #elif defined(__x86_64__) || defined(__i386__)
1687         fprintf (fp, "\t.type %s,@%s\n", name, stype);
1688 #endif
1689 }
1690
1691 static void
1692 emit_global (FILE *fp, const char *name, gboolean func)
1693 {
1694 #if  (defined(__ppc__) && defined(__MACH__)) || defined(PLATFORM_WIN32)
1695     // mach-o always uses a '_' prefix.
1696         fprintf (fp, "\t.globl _%s\n", name);
1697 #else
1698         fprintf (fp, "\t.globl %s\n", name);
1699 #endif
1700
1701         emit_symbol_type (fp, name, func);
1702 }
1703
1704 static void
1705 emit_label (FILE *fp, const char *name)
1706 {
1707 #if (defined(__ppc__) && defined(__MACH__)) || defined(PLATFORM_WIN32)
1708     // mach-o always uses a '_' prefix.
1709         fprintf (fp, "_%s:\n", name);
1710 #else
1711         fprintf (fp, "%s:\n", name);
1712 #endif
1713
1714 #if defined(PLATFORM_WIN32)
1715         /* Emit a normal label too */
1716         fprintf (fp, "%s:\n", name);
1717 #endif
1718 }
1719
1720 static void
1721 emit_string_symbol (FILE *fp, const char *name, const char *value)
1722 {
1723         emit_section_change (fp, ".text", 1);
1724         emit_global(fp, name, FALSE);
1725         emit_label(fp, name);
1726         fprintf (fp, "\t%s \"%s\"\n", AS_STRING_DIRECTIVE, value);
1727 }
1728
1729 #if defined(__ppc__) && defined(__MACH__)
1730 static int
1731 ilog2(register int value)
1732 {
1733     int count = -1;
1734     while (value & ~0xf) count += 4, value >>= 4;
1735     while (value) count++, value >>= 1;
1736     return count;
1737 }
1738 #endif
1739
1740 static void 
1741 emit_alignment(FILE *fp, int size)
1742 {
1743 #if defined(__ppc__) && defined(__MACH__)
1744         // the mach-o assembler specifies alignments as powers of 2.
1745         fprintf (fp, "\t.align %d\t; ilog2\n", ilog2(size));
1746 #elif defined(__powerpc__)
1747         /* ignore on linux/ppc */
1748 #else
1749         fprintf (fp, "\t.align %d\n", size);
1750 #endif
1751 }
1752
1753 G_GNUC_UNUSED static void
1754 emit_pointer (FILE *fp, const char *target)
1755 {
1756         emit_alignment (fp, sizeof (gpointer));
1757 #if defined(__x86_64__)
1758         fprintf (fp, "\t.quad %s\n", target);
1759 #elif defined(sparc) && SIZEOF_VOID_P == 8
1760         fprintf (fp, "\t.xword %s\n", target);
1761 #else
1762         fprintf (fp, "\t.long %s\n", target);
1763 #endif
1764 }
1765
1766 static guint32
1767 mono_get_field_token (MonoClassField *field) 
1768 {
1769         MonoClass *klass = field->parent;
1770         int i;
1771
1772         for (i = 0; i < klass->field.count; ++i) {
1773                 if (field == &klass->fields [i])
1774                         return MONO_TOKEN_FIELD_DEF | (klass->field.first + 1 + i);
1775         }
1776
1777         g_assert_not_reached ();
1778         return 0;
1779 }
1780
1781 static inline void
1782 encode_value (gint32 value, guint8 *buf, guint8 **endbuf)
1783 {
1784         guint8 *p = buf;
1785
1786         //printf ("ENCODE: %d 0x%x.\n", value, value);
1787
1788         /* 
1789          * Same encoding as the one used in the metadata, extended to handle values
1790          * greater than 0x1fffffff.
1791          */
1792         if ((value >= 0) && (value <= 127))
1793                 *p++ = value;
1794         else if ((value >= 0) && (value <= 16383)) {
1795                 p [0] = 0x80 | (value >> 8);
1796                 p [1] = value & 0xff;
1797                 p += 2;
1798         } else if ((value >= 0) && (value <= 0x1fffffff)) {
1799                 p [0] = (value >> 24) | 0xc0;
1800                 p [1] = (value >> 16) & 0xff;
1801                 p [2] = (value >> 8) & 0xff;
1802                 p [3] = value & 0xff;
1803                 p += 4;
1804         }
1805         else {
1806                 p [0] = 0xff;
1807                 p [1] = (value >> 24) & 0xff;
1808                 p [2] = (value >> 16) & 0xff;
1809                 p [3] = (value >> 8) & 0xff;
1810                 p [4] = value & 0xff;
1811                 p += 5;
1812         }
1813         if (endbuf)
1814                 *endbuf = p;
1815 }
1816
1817 static guint32
1818 get_image_index (MonoAotCompile *cfg, MonoImage *image)
1819 {
1820         guint32 index;
1821
1822         index = GPOINTER_TO_UINT (g_hash_table_lookup (cfg->image_hash, image));
1823         if (index)
1824                 return index - 1;
1825         else {
1826                 index = g_hash_table_size (cfg->image_hash);
1827                 g_hash_table_insert (cfg->image_hash, image, GUINT_TO_POINTER (index + 1));
1828                 g_ptr_array_add (cfg->image_table, image);
1829                 return index;
1830         }
1831 }
1832
1833 static void
1834 encode_klass_info (MonoAotCompile *cfg, MonoClass *klass, guint8 *buf, guint8 **endbuf)
1835 {
1836         if (!klass->type_token) {
1837                 /* Array class */
1838                 g_assert (klass->rank > 0);
1839                 g_assert (klass->element_class->type_token);
1840                 encode_value (MONO_TOKEN_TYPE_DEF, buf, &buf);
1841                 encode_value (get_image_index (cfg, klass->image), buf, &buf);
1842                 g_assert (mono_metadata_token_code (klass->element_class->type_token) == MONO_TOKEN_TYPE_DEF);
1843                 encode_value (klass->element_class->type_token - MONO_TOKEN_TYPE_DEF, buf, &buf);
1844                 encode_value (klass->rank, buf, &buf);
1845         }
1846         else {
1847                 g_assert (mono_metadata_token_code (klass->type_token) == MONO_TOKEN_TYPE_DEF);
1848                 encode_value (klass->type_token - MONO_TOKEN_TYPE_DEF, buf, &buf);
1849                 encode_value (get_image_index (cfg, klass->image), buf, &buf);
1850         }
1851         *endbuf = buf;
1852 }
1853
1854 static void
1855 encode_field_info (MonoAotCompile *cfg, MonoClassField *field, guint8 *buf, guint8 **endbuf)
1856 {
1857         guint32 token = mono_get_field_token (field);
1858
1859         encode_klass_info (cfg, field->parent, buf, &buf);
1860         g_assert (mono_metadata_token_code (token) == MONO_TOKEN_FIELD_DEF);
1861         encode_value (token - MONO_TOKEN_FIELD_DEF, buf, &buf);
1862         *endbuf = buf;
1863 }
1864
1865 static void
1866 encode_method_ref (MonoAotCompile *acfg, MonoMethod *method, guint8 *buf, guint8 **endbuf)
1867 {
1868         guint32 image_index = get_image_index (acfg, method->klass->image);
1869         guint32 token = method->token;
1870         g_assert (image_index < 256);
1871         g_assert (mono_metadata_token_table (token) == MONO_TABLE_METHOD);
1872
1873         encode_value ((image_index << 24) + (mono_metadata_token_index (token)), buf, &buf);
1874         *endbuf = buf;
1875 }
1876
1877 static gint
1878 compare_patches (gconstpointer a, gconstpointer b)
1879 {
1880         int i, j;
1881
1882         i = (*(MonoJumpInfo**)a)->ip.i;
1883         j = (*(MonoJumpInfo**)b)->ip.i;
1884
1885         if (i < j)
1886                 return -1;
1887         else
1888                 if (i > j)
1889                         return 1;
1890         else
1891                 return 0;
1892 }
1893
1894 static guint32
1895 get_got_slot (MonoAotCompile *acfg, MonoJumpInfo *patch_info)
1896 {
1897         guint32 res;
1898
1899         switch (patch_info->type) {
1900         case MONO_PATCH_INFO_IMAGE:
1901                 if (patch_info->data.image == acfg->image)
1902                         res = 0;
1903                 else {
1904                         res = acfg->got_offset;
1905                         acfg->got_offset ++;
1906                 }
1907                 break;
1908         case MONO_PATCH_INFO_INTERNAL_METHOD:
1909                 res = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->icall_to_got_offset_hash, patch_info->data.name));
1910                 break;
1911         default:
1912                 res = acfg->got_offset;
1913                 acfg->got_offset ++;
1914                 break;
1915         }
1916
1917         return res;
1918 }
1919
1920 static void
1921 collect_icalls (MonoAotCompile *acfg)
1922 {
1923         int mindex, index;
1924         MonoJumpInfo *patch_info;
1925
1926         for (mindex = 0; mindex < acfg->nmethods; ++mindex) {
1927                 MonoCompile *cfg;
1928
1929                 cfg = acfg->cfgs [mindex];
1930                 if (!cfg)
1931                         continue;
1932
1933                 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
1934                         switch (patch_info->type) {
1935                         case MONO_PATCH_INFO_INTERNAL_METHOD:
1936                                 index = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->icall_hash, patch_info->data.name));
1937                                 if (!index) {
1938                                         index = g_hash_table_size (acfg->icall_hash) + 1;
1939                                         g_hash_table_insert (acfg->icall_hash, (gpointer)patch_info->data.name,
1940                                                                                  GUINT_TO_POINTER (index));
1941                                         g_ptr_array_add (acfg->icall_table, (gpointer)patch_info->data.name);
1942
1943                                         /* Allocate a GOT slot */
1944                                         g_hash_table_insert (acfg->icall_to_got_offset_hash, (gpointer)patch_info->data.name, GUINT_TO_POINTER (acfg->got_offset));
1945                                         acfg->got_offset ++;
1946                                 }
1947                                 break;
1948                         default:
1949                                 break;
1950                         }
1951                 }
1952         }
1953 }
1954
1955 static void
1956 emit_method_code (MonoAotCompile *acfg, MonoCompile *cfg)
1957 {
1958         MonoMethod *method;
1959         FILE *tmpfp;
1960         int i, j, pindex, byte_index;
1961         guint8 *code;
1962         char *symbol;
1963         int func_alignment = 16;
1964         GPtrArray *patches;
1965         MonoJumpInfo *patch_info;
1966         MonoMethodHeader *header;
1967 #ifdef MONO_ARCH_HAVE_PIC_AOT
1968         gboolean skip;
1969         guint32 got_slot;
1970 #endif
1971
1972         tmpfp = acfg->fp;
1973         method = cfg->method;
1974         code = cfg->native_code;
1975         header = mono_method_get_header (method);
1976
1977         /* Make the labels local */
1978         symbol = g_strdup_printf (".Lm_%x", mono_metadata_token_index (method->token));
1979
1980         emit_alignment(tmpfp, func_alignment);
1981         emit_label(tmpfp, symbol);
1982         if (acfg->aot_opts.write_symbols)
1983                 emit_global (tmpfp, symbol, TRUE);
1984
1985         if (cfg->verbose_level > 0)
1986                 g_print ("Method %s emitted as %s\n", mono_method_full_name (method, TRUE), symbol);
1987
1988         acfg->code_size += cfg->code_len;
1989
1990         /* Sort relocations */
1991         patches = g_ptr_array_new ();
1992         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next)
1993                 g_ptr_array_add (patches, patch_info);
1994         g_ptr_array_sort (patches, compare_patches);
1995
1996 #ifdef MONO_ARCH_HAVE_PIC_AOT
1997         acfg->method_got_offsets [mono_metadata_token_index (method->token)] = acfg->got_offset;
1998         byte_index = 0;
1999         for (i = 0; i < cfg->code_len; i++) {
2000                 patch_info = NULL;
2001                 for (pindex = 0; pindex < patches->len; ++pindex) {
2002                         patch_info = g_ptr_array_index (patches, pindex);
2003                         if (patch_info->ip.i == i)
2004                                 break;
2005                 }
2006
2007                 skip = FALSE;
2008                 if (patch_info && (pindex < patches->len)) {
2009                         switch (patch_info->type) {
2010                         case MONO_PATCH_INFO_LABEL:
2011                         case MONO_PATCH_INFO_BB:
2012                         case MONO_PATCH_INFO_NONE:
2013                                 break;
2014                         case MONO_PATCH_INFO_GOT_OFFSET: {
2015                                 guint32 offset = mono_arch_get_patch_offset (code + i);
2016                                 fprintf (tmpfp, "\n.byte ");
2017                                 for (j = 0; j < offset; ++j)
2018                                         fprintf (tmpfp, "%s0x%x", (j == 0) ? "" : ",", (unsigned int) code [i + j]);
2019                                 fprintf (tmpfp, "\n.int got - . + %d", offset);
2020
2021                                 i += offset + 4 - 1;
2022                                 skip = TRUE;
2023                                 break;
2024                         }
2025                         default:
2026                                 if (!is_got_patch (patch_info->type))
2027                                         break;
2028
2029                                 got_slot = get_got_slot (acfg, patch_info);
2030                                 fprintf (tmpfp, "\n.byte ");
2031                                 for (j = 0; j < mono_arch_get_patch_offset (code + i); ++j)
2032                                         fprintf (tmpfp, "%s0x%x", (j == 0) ? "" : ",", (unsigned int) code [i + j]);
2033 #ifdef __x86_64__
2034                                 fprintf (tmpfp, "\n.int got - . + %d", (unsigned int) ((got_slot * sizeof (gpointer)) - 4));
2035 #elif defined(__i386__)
2036                                 fprintf (tmpfp, "\n.int %d\n", (unsigned int) ((got_slot * sizeof (gpointer))));
2037 #endif
2038
2039                                 i += mono_arch_get_patch_offset (code + i) + 4 - 1;
2040                                 skip = TRUE;
2041                         }
2042                 }
2043
2044                 if (!skip) {
2045                         if (byte_index == 0)
2046                                 fprintf (tmpfp, "\n.byte ");
2047                         fprintf (tmpfp, "%s0x%x", (byte_index == 0) ? "" : ",", (unsigned int) code [i]);
2048                         byte_index = (byte_index + 1) % 32;
2049                 }
2050                 else
2051                         byte_index = 0;
2052         }
2053 #else
2054         for (i = 0; i < cfg->code_len; i++) {
2055                 fprintf (tmpfp, ".byte 0x%x\n", (unsigned int) code [i]);
2056         }
2057 #endif
2058         fprintf (tmpfp, "\n");
2059 }
2060
2061 static void
2062 emit_method_info (MonoAotCompile *acfg, MonoCompile *cfg)
2063 {
2064         MonoMethod *method;
2065         GList *l;
2066         FILE *tmpfp;
2067         int i, j, pindex, buf_size, n_patches;
2068         guint8 *code;
2069         char *symbol;
2070         GPtrArray *patches;
2071         MonoJumpInfo *patch_info;
2072         MonoMethodHeader *header;
2073         guint32 last_offset;
2074         guint8 *p, *buf;
2075 #ifdef MONO_ARCH_HAVE_PIC_AOT
2076         guint32 first_got_offset;
2077 #endif
2078
2079         tmpfp = acfg->fp;
2080         method = cfg->method;
2081         code = cfg->native_code;
2082         header = mono_method_get_header (method);
2083
2084         /* Make the labels local */
2085         symbol = g_strdup_printf (".Lm_%x_p", mono_metadata_token_index (method->token));
2086
2087         /* Sort relocations */
2088         patches = g_ptr_array_new ();
2089         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next)
2090                 g_ptr_array_add (patches, patch_info);
2091         g_ptr_array_sort (patches, compare_patches);
2092
2093 #ifdef MONO_ARCH_HAVE_PIC_AOT
2094         first_got_offset = acfg->method_got_offsets [mono_metadata_token_index (cfg->method->token)];
2095 #endif
2096
2097         /**********************/
2098         /* Encode method info */
2099         /**********************/
2100
2101         buf_size = (patches->len < 1000) ? 40960 : 40960 + (patches->len * 64);
2102         p = buf = g_malloc (buf_size);
2103
2104         if (mono_class_get_cctor (method->klass))
2105                 encode_klass_info (acfg, method->klass, p, &p);
2106         else
2107                 /* Not needed when loading the method */
2108                 encode_value (0, p, &p);
2109
2110         /* String table */
2111         if (cfg->opt & MONO_OPT_SHARED) {
2112                 encode_value (g_list_length (cfg->ldstr_list), p, &p);
2113                 for (l = cfg->ldstr_list; l; l = l->next) {
2114                         encode_value ((long)l->data, p, &p);
2115                 }
2116         }
2117         else
2118                 /* Used only in shared mode */
2119                 g_assert (!cfg->ldstr_list);
2120
2121 #ifdef MONO_ARCH_HAVE_PIC_AOT
2122         encode_value (first_got_offset, p, &p);
2123 #endif
2124
2125         n_patches = 0;
2126         for (pindex = 0; pindex < patches->len; ++pindex) {
2127                 patch_info = g_ptr_array_index (patches, pindex);
2128                 
2129                 if ((patch_info->type == MONO_PATCH_INFO_LABEL) ||
2130                         (patch_info->type == MONO_PATCH_INFO_BB) ||
2131                         (patch_info->type == MONO_PATCH_INFO_GOT_OFFSET) ||
2132                         (patch_info->type == MONO_PATCH_INFO_NONE)) {
2133                         patch_info->type = MONO_PATCH_INFO_NONE;
2134                         /* Nothing to do */
2135                         continue;
2136                 }
2137
2138                 if ((patch_info->type == MONO_PATCH_INFO_IMAGE) && (patch_info->data.image == acfg->image)) {
2139                         /* Stored in GOT slot 0 */
2140                         patch_info->type = MONO_PATCH_INFO_NONE;
2141                         continue;
2142                 }
2143
2144                 n_patches ++;
2145         }
2146
2147         encode_value (n_patches, p, &p);
2148
2149         /* First emit the type+position table */
2150         last_offset = 0;
2151         j = 0;
2152         for (pindex = 0; pindex < patches->len; ++pindex) {
2153                 guint32 offset;
2154                 patch_info = g_ptr_array_index (patches, pindex);
2155                 
2156                 if (patch_info->type == MONO_PATCH_INFO_NONE)
2157                         /* Nothing to do */
2158                         continue;
2159
2160                 j ++;
2161                 //printf ("T: %d O: %d.\n", patch_info->type, patch_info->ip.i);
2162                 offset = patch_info->ip.i - last_offset;
2163                 last_offset = patch_info->ip.i;
2164
2165 #if defined(MONO_ARCH_HAVE_PIC_AOT)
2166                 /* Only the type is needed */
2167                 *p = patch_info->type;
2168                 p++;
2169 #else
2170                 /* Encode type+position compactly */
2171                 g_assert (patch_info->type < 64);
2172                 if (offset < 1024 - 1) {
2173                         *p = (patch_info->type << 2) + (offset >> 8);
2174                         p++;
2175                         *p = offset & ((1 << 8) - 1);
2176                         p ++;
2177                 }
2178                 else {
2179                         *p = (patch_info->type << 2) + 3;
2180                         p ++;
2181                         *p = 255;
2182                         p ++;
2183                         encode_value (offset, p, &p);
2184                 }
2185 #endif
2186         }
2187
2188         /* Then emit the other info */
2189         for (pindex = 0; pindex < patches->len; ++pindex) {
2190                 patch_info = g_ptr_array_index (patches, pindex);
2191
2192                 switch (patch_info->type) {
2193                 case MONO_PATCH_INFO_NONE:
2194                         break;
2195                 case MONO_PATCH_INFO_IMAGE:
2196                         encode_value (get_image_index (acfg, patch_info->data.image), p, &p);
2197                         break;
2198                 case MONO_PATCH_INFO_METHOD_REL:
2199                         encode_value ((gint)patch_info->data.offset, p, &p);
2200                         break;
2201                 case MONO_PATCH_INFO_SWITCH: {
2202                         gpointer *table = (gpointer *)patch_info->data.table->table;
2203                         int k;
2204
2205                         encode_value (patch_info->data.table->table_size, p, &p);
2206                         for (k = 0; k < patch_info->data.table->table_size; k++)
2207                                 encode_value ((int)(gssize)table [k], p, &p);
2208                         break;
2209                 }
2210                 case MONO_PATCH_INFO_METHODCONST:
2211                 case MONO_PATCH_INFO_METHOD:
2212                 case MONO_PATCH_INFO_METHOD_JUMP:
2213                         encode_method_ref (acfg, patch_info->data.method, p, &p);
2214                         break;
2215                 case MONO_PATCH_INFO_INTERNAL_METHOD: {
2216                         guint32 icall_index;
2217
2218                         icall_index = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->icall_hash, patch_info->data.name));
2219                         g_assert (icall_index);
2220                         encode_value (icall_index - 1, p, &p);
2221                         break;
2222                 }
2223                 case MONO_PATCH_INFO_LDSTR: {
2224                         guint32 image_index = get_image_index (acfg, patch_info->data.token->image);
2225                         guint32 token = patch_info->data.token->token;
2226                         g_assert (mono_metadata_token_code (token) == MONO_TOKEN_STRING);
2227                         /* 
2228                          * An optimization would be to emit shared code for ldstr 
2229                          * statements followed by a throw.
2230                          */
2231                         encode_value (image_index, p, &p);
2232                         encode_value (patch_info->data.token->token - MONO_TOKEN_STRING, p, &p);
2233                         break;
2234                 }
2235                 case MONO_PATCH_INFO_DECLSEC:
2236                 case MONO_PATCH_INFO_LDTOKEN:
2237                 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
2238                         encode_value (get_image_index (acfg, patch_info->data.token->image), p, &p);
2239                         encode_value (patch_info->data.token->token, p, &p);
2240                         break;
2241                 case MONO_PATCH_INFO_EXC_NAME: {
2242                         MonoClass *ex_class;
2243
2244                         ex_class =
2245                                 mono_class_from_name (mono_defaults.exception_class->image,
2246                                                                           "System", patch_info->data.target);
2247                         g_assert (ex_class);
2248                         encode_klass_info (acfg, ex_class, p, &p);
2249                         break;
2250                 }
2251                 case MONO_PATCH_INFO_R4:
2252                         encode_value (*((guint32 *)patch_info->data.target), p, &p);
2253                         break;
2254                 case MONO_PATCH_INFO_R8:
2255                         encode_value (*((guint32 *)patch_info->data.target), p, &p);
2256                         encode_value (*(((guint32 *)patch_info->data.target) + 1), p, &p);
2257                         break;
2258                 case MONO_PATCH_INFO_VTABLE:
2259                 case MONO_PATCH_INFO_CLASS_INIT:
2260                 case MONO_PATCH_INFO_CLASS:
2261                 case MONO_PATCH_INFO_IID:
2262                         encode_klass_info (acfg, patch_info->data.klass, p, &p);
2263                         break;
2264                 case MONO_PATCH_INFO_FIELD:
2265                 case MONO_PATCH_INFO_SFLDA:
2266                         encode_field_info (acfg, patch_info->data.field, p, &p);
2267                         break;
2268                 case MONO_PATCH_INFO_WRAPPER: {
2269                         encode_value (patch_info->data.method->wrapper_type, p, &p);
2270
2271                         switch (patch_info->data.method->wrapper_type) {
2272                         case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK: {
2273                                 MonoMethod *m;
2274                                 guint32 image_index;
2275                                 guint32 token;
2276
2277                                 m = mono_marshal_method_from_wrapper (patch_info->data.method);
2278                                 image_index = get_image_index (acfg, m->klass->image);
2279                                 token = m->token;
2280                                 g_assert (image_index < 256);
2281                                 g_assert (mono_metadata_token_table (token) == MONO_TABLE_METHOD);
2282
2283                                 encode_value ((image_index << 24) + (mono_metadata_token_index (token)), p, &p);
2284                                 break;
2285                         }
2286                         case MONO_WRAPPER_PROXY_ISINST:
2287                         case MONO_WRAPPER_LDFLD:
2288                         case MONO_WRAPPER_LDFLDA:
2289                         case MONO_WRAPPER_STFLD:
2290                         case MONO_WRAPPER_LDFLD_REMOTE:
2291                         case MONO_WRAPPER_STFLD_REMOTE:
2292                         case MONO_WRAPPER_ISINST: {
2293                                 MonoClass *proxy_class = (MonoClass*)mono_marshal_method_from_wrapper (patch_info->data.method);
2294                                 encode_klass_info (acfg, proxy_class, p, &p);
2295                                 break;
2296                         }
2297                         case MONO_WRAPPER_STELEMREF:
2298                                 break;
2299                         default:
2300                                 g_assert_not_reached ();
2301                         }
2302                         break;
2303                 }
2304                 default:
2305                         g_warning ("unable to handle jump info %d", patch_info->type);
2306                         g_assert_not_reached ();
2307                 }
2308         }
2309
2310         acfg->info_size += p - buf;
2311
2312         /* Emit method info */
2313
2314         emit_label (tmpfp, symbol);
2315
2316         g_assert (p - buf < buf_size);
2317         for (i = 0; i < p - buf; ++i) {
2318                 if ((i % 32) == 0)
2319                         fprintf (tmpfp, "\n.byte ");
2320                 fprintf (tmpfp, "%s%d", ((i % 32) == 0) ? "" : ",", (unsigned int) buf [i]);
2321         }
2322         fprintf (tmpfp, "\n");
2323         g_free (buf);
2324
2325         g_free (symbol);
2326 }
2327
2328 static void
2329 emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg)
2330 {
2331         MonoMethod *method;
2332         FILE *tmpfp;
2333         int i, k, buf_size;
2334         guint32 debug_info_size;
2335         guint8 *code;
2336         char *symbol;
2337         MonoMethodHeader *header;
2338         guint8 *p, *buf, *debug_info;
2339
2340         tmpfp = acfg->fp;
2341         method = cfg->method;
2342         code = cfg->native_code;
2343         header = mono_method_get_header (method);
2344
2345         /* Make the labels local */
2346         symbol = g_strdup_printf (".Le_%x_p", mono_metadata_token_index (method->token));
2347
2348         buf_size = header->num_clauses * 256 + 128;
2349         p = buf = g_malloc (buf_size);
2350
2351         encode_value (cfg->code_len, p, &p);
2352         encode_value (cfg->used_int_regs, p, &p);
2353
2354         /* Exception table */
2355         if (header->num_clauses) {
2356                 MonoJitInfo *jinfo = cfg->jit_info;
2357
2358                 for (k = 0; k < header->num_clauses; ++k) {
2359                         MonoJitExceptionInfo *ei = &jinfo->clauses [k];
2360
2361                         encode_value (ei->exvar_offset, p, &p);
2362
2363                         if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)
2364                                 encode_value ((gint)((guint8*)ei->data.filter - code), p, &p);
2365
2366                         encode_value ((gint)((guint8*)ei->try_start - code), p, &p);
2367                         encode_value ((gint)((guint8*)ei->try_end - code), p, &p);
2368                         encode_value ((gint)((guint8*)ei->handler_start - code), p, &p);
2369                 }
2370         }
2371
2372         mono_debug_serialize_debug_info (cfg, &debug_info, &debug_info_size);
2373
2374         encode_value (debug_info_size, p, &p);
2375         if (debug_info_size) {
2376                 memcpy (p, debug_info, debug_info_size);
2377                 p += debug_info_size;
2378                 g_free (debug_info);
2379         }
2380
2381         acfg->ex_info_size += p - buf;
2382
2383         /* Emit info */
2384
2385         emit_label (tmpfp, symbol);
2386
2387         g_assert (p - buf < buf_size);
2388         for (i = 0; i < p - buf; ++i) {
2389                 if ((i % 32) == 0)
2390                         fprintf (tmpfp, "\n.byte ");
2391                 fprintf (tmpfp, "%s%d", ((i % 32) == 0) ? "" : ",", (unsigned int) buf [i]);
2392         }
2393         fprintf (tmpfp, "\n");
2394         g_free (buf);
2395
2396         g_free (symbol);
2397 }
2398
2399 static void
2400 emit_klass_info (MonoAotCompile *acfg, guint32 token)
2401 {
2402         MonoClass *klass = mono_class_get (acfg->image, token);
2403         guint8 *p, *buf;
2404         int i, buf_size;
2405         char *label;
2406         FILE *tmpfp = acfg->fp;
2407         gboolean no_special_static;
2408
2409         buf_size = 10240;
2410         p = buf = g_malloc (buf_size);
2411
2412         g_assert (klass);
2413
2414         mono_class_init (klass);
2415
2416         /* 
2417          * Emit all the information which is required for creating vtables so
2418          * the runtime does not need to create the MonoMethod structures which
2419          * take up a lot of space.
2420          */
2421
2422         no_special_static = !mono_class_has_special_static_fields (klass);
2423
2424         if (1) {
2425                 encode_value (klass->vtable_size, p, &p);
2426                 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);
2427                 if (klass->has_cctor)
2428                         encode_method_ref (acfg, mono_class_get_cctor (klass), p, &p);
2429                 if (klass->has_finalize)
2430                         encode_method_ref (acfg, mono_class_get_finalizer (klass), p, &p);
2431  
2432                 encode_value (klass->instance_size, p, &p);
2433                 encode_value (klass->class_size, p, &p);
2434                 encode_value (klass->packing_size, p, &p);
2435                 encode_value (klass->min_align, p, &p);
2436
2437                 for (i = 0; i < klass->vtable_size; ++i) {
2438                         MonoMethod *cm = klass->vtable [i];
2439
2440                         if (cm)
2441                                 encode_method_ref (acfg, cm, p, &p);
2442                         else
2443                                 encode_value (0, p, &p);
2444                 }
2445         }
2446
2447         acfg->class_info_size += p - buf;
2448
2449         /* Emit the info */
2450         label = g_strdup_printf (".LK_I_%x", token - MONO_TOKEN_TYPE_DEF - 1);
2451         emit_label (tmpfp, label);
2452
2453         g_assert (p - buf < buf_size);
2454         for (i = 0; i < p - buf; ++i) {
2455                 if ((i % 32) == 0)
2456                         fprintf (tmpfp, "\n.byte ");
2457                 fprintf (tmpfp, "%s%d", ((i % 32) == 0) ? "" : ",", (unsigned int) buf [i]);
2458         }
2459         fprintf (tmpfp, "\n");
2460         g_free (buf);
2461 }
2462
2463 static gboolean
2464 str_begins_with (const char *str1, const char *str2)
2465 {
2466         int len = strlen (str2);
2467         return strncmp (str1, str2, len) == 0;
2468 }
2469
2470 static void
2471 mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts)
2472 {
2473         gchar **args, **ptr;
2474
2475         memset (opts, 0, sizeof (*opts));
2476
2477         args = g_strsplit (aot_options ? aot_options : "", ",", -1);
2478         for (ptr = args; ptr && *ptr; ptr ++) {
2479                 const char *arg = *ptr;
2480
2481                 if (str_begins_with (arg, "outfile=")) {
2482                         opts->outfile = g_strdup (arg + strlen ("outfile="));
2483                 } else if (str_begins_with (arg, "save-temps")) {
2484                         opts->save_temps = TRUE;
2485                 } else if (str_begins_with (arg, "write-symbols")) {
2486                         opts->write_symbols = TRUE;
2487                 } else {
2488                         fprintf (stderr, "AOT : Unknown argument '%s'.\n", arg);
2489                         exit (1);
2490                 }
2491         }
2492 }
2493
2494 static void
2495 compile_method (MonoAotCompile *acfg, int index)
2496 {
2497         MonoCompile *cfg;
2498         MonoMethod *method;
2499         MonoJumpInfo *patch_info;
2500         gboolean skip;
2501         guint32 token = MONO_TOKEN_METHOD_DEF | (index + 1);
2502         
2503         method = mono_get_method (acfg->image, token, NULL);
2504                 
2505         /* fixme: maybe we can also precompile wrapper methods */
2506         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
2507                 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
2508                 (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
2509                 (method->flags & METHOD_ATTRIBUTE_ABSTRACT)) {
2510                 //printf ("Skip (impossible): %s\n", mono_method_full_name (method, TRUE));
2511                 return;
2512         }
2513
2514         acfg->mcount++;
2515
2516         /* fixme: we need to patch the IP for the LMF in that case */
2517         if (method->save_lmf) {
2518                 //printf ("Skip (needs lmf):  %s\n", mono_method_full_name (method, TRUE));
2519                 acfg->lmfcount++;
2520                 return;
2521         }
2522
2523         /*
2524          * Since these methods are the only ones which are compiled with
2525          * AOT support, and they are not used by runtime startup/shutdown code,
2526          * the runtime will not see AOT methods during AOT compilation,so it
2527          * does not need to support them by creating a fake GOT etc.
2528          */
2529         cfg = mini_method_compile (method, acfg->opts, mono_get_root_domain (), FALSE, TRUE, 0);
2530         if (cfg->exception_type != MONO_EXCEPTION_NONE) {
2531                 /* Let the exception happen at runtime */
2532                 return;
2533         }
2534
2535         if (cfg->disable_aot) {
2536                 //printf ("Skip (other): %s\n", mono_method_full_name (method, TRUE));
2537                 acfg->ocount++;
2538                 mono_destroy_compile (cfg);
2539                 return;
2540         }
2541
2542         skip = FALSE;
2543         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
2544                 if (patch_info->type == MONO_PATCH_INFO_ABS) {
2545                         /* unable to handle this */
2546                         //printf ("Skip (abs addr):   %s %d\n", mono_method_full_name (method, TRUE), patch_info->type);
2547                         skip = TRUE;    
2548                         break;
2549                 }
2550         }
2551
2552         if (skip) {
2553                 acfg->abscount++;
2554                 mono_destroy_compile (cfg);
2555                 return;
2556         }
2557
2558         /* some wrappers are very common */
2559         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
2560                 if (patch_info->type == MONO_PATCH_INFO_METHODCONST) {
2561                         switch (patch_info->data.method->wrapper_type) {
2562                         case MONO_WRAPPER_PROXY_ISINST:
2563                                 patch_info->type = MONO_PATCH_INFO_WRAPPER;
2564                         }
2565                 }
2566
2567                 if (patch_info->type == MONO_PATCH_INFO_METHOD) {
2568                         switch (patch_info->data.method->wrapper_type) {
2569                         case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK:
2570                         case MONO_WRAPPER_STFLD:
2571                         case MONO_WRAPPER_LDFLD:
2572                         case MONO_WRAPPER_LDFLDA:
2573                         case MONO_WRAPPER_LDFLD_REMOTE:
2574                         case MONO_WRAPPER_STFLD_REMOTE:
2575                         case MONO_WRAPPER_STELEMREF:
2576                         case MONO_WRAPPER_ISINST:
2577                         case MONO_WRAPPER_PROXY_ISINST:
2578                                 patch_info->type = MONO_PATCH_INFO_WRAPPER;
2579                                 break;
2580                         }
2581                 }
2582         }
2583
2584         skip = FALSE;
2585         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
2586                 switch (patch_info->type) {
2587                 case MONO_PATCH_INFO_METHOD:
2588                 case MONO_PATCH_INFO_METHODCONST:
2589                         if (patch_info->data.method->wrapper_type) {
2590                                 /* unable to handle this */
2591                                 //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));
2592                                 skip = TRUE;
2593                                 break;
2594                         }
2595                         if (!patch_info->data.method->token)
2596                                 /*
2597                                  * The method is part of a constructed type like Int[,].Set (). It doesn't
2598                                  * have a token, and we can't make one, since the parent type is part of
2599                                  * assembly which contains the element type, and not the assembly which
2600                                  * referenced this type.
2601                                  */
2602                                 skip = TRUE;
2603                         break;
2604                 case MONO_PATCH_INFO_VTABLE:
2605                 case MONO_PATCH_INFO_CLASS_INIT:
2606                 case MONO_PATCH_INFO_CLASS:
2607                 case MONO_PATCH_INFO_IID:
2608                         if (!patch_info->data.klass->type_token)
2609                                 if (!patch_info->data.klass->element_class->type_token)
2610                                         skip = TRUE;
2611                         break;
2612                 default:
2613                         break;
2614                 }
2615         }
2616
2617         if (skip) {
2618                 acfg->wrappercount++;
2619                 mono_destroy_compile (cfg);
2620                 return;
2621         }
2622
2623         //printf ("Compile:           %s\n", mono_method_full_name (method, TRUE));
2624
2625         acfg->cfgs [index] = cfg;
2626
2627         acfg->ccount++;
2628 }
2629
2630 static void
2631 load_profile_files (MonoAotCompile *acfg)
2632 {
2633         FILE *infile;
2634         char *tmp;
2635         int file_index, res, method_index, i;
2636         char ver [256];
2637         guint32 token;
2638
2639         file_index = 0;
2640         while (TRUE) {
2641                 tmp = g_strdup_printf ("%s/.mono/aot-profile-data/%s-%s-%d", g_get_home_dir (), acfg->image->assembly_name, acfg->image->guid, file_index);
2642
2643                 if (!g_file_test (tmp, G_FILE_TEST_IS_REGULAR))
2644                         break;
2645
2646                 infile = fopen (tmp, "r");
2647                 g_assert (infile);
2648
2649                 printf ("Using profile data file '%s'\n", tmp);
2650
2651                 file_index ++;
2652
2653                 res = fscanf (infile, "%32s\n", ver);
2654                 if ((res != 1) || strcmp (ver, "#VER:1") != 0) {
2655                         printf ("Profile file has wrong version or invalid.\n");
2656                         continue;
2657                 }
2658
2659                 while (TRUE) {
2660                         res = fscanf (infile, "%d\n", &token);
2661                         if (res < 1)
2662                                 break;
2663
2664                         method_index = mono_metadata_token_index (token) - 1;
2665
2666                         if (!g_list_find (acfg->method_order, GUINT_TO_POINTER (method_index)))
2667                                 acfg->method_order = g_list_append (acfg->method_order, GUINT_TO_POINTER (method_index));
2668                 }
2669         }
2670
2671         /* Add missing methods */
2672         for (i = 0; i < acfg->image->tables [MONO_TABLE_METHOD].rows; ++i) {
2673                 if (!g_list_find (acfg->method_order, GUINT_TO_POINTER (i)))
2674                         acfg->method_order = g_list_append (acfg->method_order, GUINT_TO_POINTER (i));
2675         }               
2676 }
2677
2678 static void
2679 emit_method_order (MonoAotCompile *acfg)
2680 {
2681         int i, index, len;
2682         char *symbol;
2683         GList *l;
2684
2685         symbol = g_strdup_printf ("method_order");
2686         emit_section_change (acfg->fp, ".text", 1);
2687         emit_global (acfg->fp, symbol, FALSE);
2688         emit_alignment (acfg->fp, 8);
2689         emit_label(acfg->fp, symbol);
2690
2691         /* First emit an index table */
2692         index = 0;
2693         len = 0;
2694         for (l = acfg->method_order; l != NULL; l = l->next) {
2695                 i = GPOINTER_TO_UINT (l->data);
2696
2697                 if (acfg->cfgs [i]) {
2698                         if ((index % 1024) == 0) {
2699                                 fprintf (acfg->fp, ".long %d\n", i);
2700                         }
2701
2702                         index ++;
2703                 }
2704
2705                 len ++;
2706         }
2707         fprintf (acfg->fp, ".long 0xffffff\n");
2708
2709         /* Then emit the whole method order */
2710         for (l = acfg->method_order; l != NULL; l = l->next) {
2711                 i = GPOINTER_TO_UINT (l->data);
2712
2713                 if (acfg->cfgs [i]) {
2714                         fprintf (acfg->fp, ".long %d\n", i);
2715                 }
2716         }       
2717         fprintf (acfg->fp, "\n");
2718
2719         symbol = g_strdup_printf ("method_order_end");
2720         emit_section_change (acfg->fp, ".text", 1);
2721         emit_global (acfg->fp, symbol, FALSE);
2722         emit_alignment (acfg->fp, 8);
2723         emit_label(acfg->fp, symbol);
2724 }
2725
2726 int
2727 mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
2728 {
2729         MonoImage *image = ass->image;
2730         char *com, *tmpfname, *opts_str, *symbol;
2731         FILE *tmpfp;
2732         int i;
2733         MonoAotCompile *acfg;
2734         MonoCompile **cfgs;
2735         char *outfile_name, *tmp_outfile_name;
2736         GList *l;
2737
2738         printf ("Mono Ahead of Time compiler - compiling assembly %s\n", image->name);
2739
2740         acfg = g_new0 (MonoAotCompile, 1);
2741         acfg->icall_hash = g_hash_table_new (NULL, NULL);
2742         acfg->icall_to_got_offset_hash = g_hash_table_new (NULL, NULL);
2743         acfg->icall_table = g_ptr_array_new ();
2744         acfg->image_hash = g_hash_table_new (NULL, NULL);
2745         acfg->image_table = g_ptr_array_new ();
2746         acfg->image = image;
2747         acfg->opts = opts;
2748
2749         mono_aot_parse_options (aot_options, &acfg->aot_opts);
2750
2751         load_profile_files (acfg);
2752
2753         i = g_file_open_tmp ("mono_aot_XXXXXX", &tmpfname, NULL);
2754         tmpfp = fdopen (i, "w+");
2755         acfg->fp = tmpfp;
2756         g_assert (tmpfp);
2757
2758         emit_string_symbol (tmpfp, "mono_assembly_guid" , image->guid);
2759
2760         emit_string_symbol (tmpfp, "mono_aot_version", MONO_AOT_FILE_VERSION);
2761
2762         opts_str = g_strdup_printf ("%d", opts);
2763         emit_string_symbol (tmpfp, "mono_aot_opt_flags", opts_str);
2764         g_free (opts_str);
2765
2766         cfgs = g_new0 (MonoCompile*, image->tables [MONO_TABLE_METHOD].rows + 32);
2767         acfg->cfgs = cfgs;
2768         acfg->nmethods = image->tables [MONO_TABLE_METHOD].rows;
2769         acfg->method_got_offsets = g_new0 (guint32, image->tables [MONO_TABLE_METHOD].rows + 32);
2770
2771         /* Compile methods */
2772         for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i)
2773                 compile_method (acfg, i);
2774
2775         /* Reserved slots */
2776         acfg->got_offset = N_RESERVED_GOT_SLOTS;
2777
2778         collect_icalls (acfg);
2779
2780         /* Emit code */
2781         symbol = g_strdup_printf ("methods");
2782         emit_section_change (tmpfp, ".text", 0);
2783         emit_global (tmpfp, symbol, TRUE);
2784         emit_alignment (tmpfp, 8);
2785         emit_label (tmpfp, symbol);
2786
2787         for (l = acfg->method_order; l != NULL; l = l->next) {
2788                 i = GPOINTER_TO_UINT (l->data);
2789
2790                 if (cfgs [i])
2791                         emit_method_code (acfg, cfgs [i]);
2792         }
2793
2794         symbol = g_strdup_printf ("methods_end");
2795         emit_section_change (tmpfp, ".text", 0);
2796         emit_global (tmpfp, symbol, FALSE);
2797         emit_alignment (tmpfp, 8);
2798         emit_label (tmpfp, symbol);
2799
2800         /* Emit method_offsets table */
2801         symbol = g_strdup_printf ("method_offsets");
2802         emit_section_change (tmpfp, ".text", 1);
2803         emit_global (tmpfp, symbol, FALSE);
2804         emit_alignment (tmpfp, 8);
2805         emit_label(tmpfp, symbol);
2806
2807         for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
2808                 const char *sep;
2809                 if ((i % 32) == 0) {
2810                         fprintf (tmpfp, "\n.long ");
2811                         sep = "";
2812                 }
2813                 else
2814                         sep = ",";
2815                 if (cfgs [i]) {
2816                         symbol = g_strdup_printf (".Lm_%x", i + 1);
2817                         fprintf (tmpfp, "%s%s-methods", sep, symbol);
2818                 }
2819                 else
2820                         fprintf (tmpfp, "%s0xffffffff", sep);
2821         }
2822         fprintf (tmpfp, "\n");
2823
2824         /* Emit method info */
2825         symbol = g_strdup_printf ("method_infos");
2826         emit_section_change (tmpfp, ".text", 1);
2827         emit_global (tmpfp, symbol, FALSE);
2828         emit_alignment (tmpfp, 8);
2829         emit_label (tmpfp, symbol);
2830
2831         /* To reduce size of generated assembly code */
2832         symbol = g_strdup_printf ("mi");
2833         emit_label (tmpfp, symbol);
2834
2835         for (l = acfg->method_order; l != NULL; l = l->next) {
2836                 i = GPOINTER_TO_UINT (l->data);
2837
2838                 if (cfgs [i])
2839                         emit_method_info (acfg, cfgs [i]);
2840         }
2841
2842         symbol = g_strdup_printf ("method_info_offsets");
2843         emit_section_change (tmpfp, ".text", 1);
2844         emit_global (tmpfp, symbol, FALSE);
2845         emit_alignment (tmpfp, 8);
2846         emit_label(tmpfp, symbol);
2847
2848         for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
2849                 const char *sep;
2850                 if ((i % 32) == 0) {
2851                         fprintf (tmpfp, "\n.long ");
2852                         sep = "";
2853                 }
2854                 else
2855                         sep = ",";
2856                 if (cfgs [i]) {
2857                         symbol = g_strdup_printf (".Lm_%x_p", i + 1);
2858                         fprintf (tmpfp, "%s%s - mi", sep, symbol);
2859                 }
2860                 else
2861                         fprintf (tmpfp, "%s0", sep);
2862         }
2863         fprintf (tmpfp, "\n");
2864
2865         /* Emit exception info */
2866         symbol = g_strdup_printf ("ex_infos");
2867         emit_section_change (tmpfp, ".text", 1);
2868         emit_global (tmpfp, symbol, FALSE);
2869         emit_alignment (tmpfp, 8);
2870         emit_label (tmpfp, symbol);
2871
2872         /* To reduce size of generate assembly */
2873         symbol = g_strdup_printf ("ex");
2874         emit_label (tmpfp, symbol);
2875
2876         for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
2877                 if (cfgs [i])
2878                         emit_exception_debug_info (acfg, cfgs [i]);
2879         }
2880
2881         symbol = g_strdup_printf ("ex_info_offsets");
2882         emit_section_change (tmpfp, ".text", 1);
2883         emit_global (tmpfp, symbol, FALSE);
2884         emit_alignment (tmpfp, 8);
2885         emit_label(tmpfp, symbol);
2886
2887         for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
2888                 const char *sep;
2889                 if ((i % 32) == 0) {
2890                         fprintf (tmpfp, "\n.long ");
2891                         sep = "";
2892                 }
2893                 else
2894                         sep = ",";
2895                 if (cfgs [i]) {
2896                         symbol = g_strdup_printf (".Le_%x_p", i + 1);
2897                         fprintf (tmpfp, "%s%s - ex", sep, symbol);
2898                 }
2899                 else
2900                         fprintf (tmpfp, "%s0", sep);
2901         }
2902         fprintf (tmpfp, "\n");
2903
2904         /* Emit method_order table */
2905         emit_method_order (acfg);
2906
2907         /* Emit class info */
2908         symbol = g_strdup_printf ("class_infos");
2909         emit_section_change (tmpfp, ".text", 1);
2910         emit_global (tmpfp, symbol, FALSE);
2911         emit_alignment (tmpfp, 8);
2912         emit_label (tmpfp, symbol);
2913
2914         for (i = 0; i < image->tables [MONO_TABLE_TYPEDEF].rows; ++i)
2915                 emit_klass_info (acfg, MONO_TOKEN_TYPE_DEF | (i + 1));
2916
2917         symbol = g_strdup_printf ("class_info_offsets");
2918         emit_section_change (tmpfp, ".text", 1);
2919         emit_global (tmpfp, symbol, FALSE);
2920         emit_alignment (tmpfp, 8);
2921         emit_label(tmpfp, symbol);
2922
2923         for (i = 0; i < image->tables [MONO_TABLE_TYPEDEF].rows; ++i) {
2924                 const char *sep;
2925                 if ((i % 32) == 0) {
2926                         fprintf (tmpfp, "\n.long ");
2927                         sep = "";
2928                 }
2929                 else
2930                         sep = ",";
2931
2932                 symbol = g_strdup_printf (".LK_I_%x", i);
2933                 fprintf (tmpfp, "%s%s - class_infos", sep, symbol);
2934         }
2935         fprintf (tmpfp, "\n");
2936
2937         /*
2938          * The icall and image tables are small but referenced in a lot of places.
2939          * So we emit them at once, and reference their elements by an index.
2940          */
2941
2942         /* Emit icall table */
2943
2944         symbol = g_strdup_printf ("mono_icall_table");
2945         emit_section_change (tmpfp, ".text", 1);
2946         emit_global(tmpfp, symbol, FALSE);
2947         emit_alignment(tmpfp, 8);
2948         emit_label(tmpfp, symbol);
2949         fprintf (tmpfp, ".long %d\n", acfg->icall_table->len);
2950         for (i = 0; i < acfg->icall_table->len; i++)
2951                 fprintf (tmpfp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, (char*)g_ptr_array_index (acfg->icall_table, i));
2952
2953         /* Emit image table */
2954
2955         symbol = g_strdup_printf ("mono_image_table");
2956         emit_section_change (tmpfp, ".text", 1);
2957         emit_global(tmpfp, symbol, FALSE);
2958         emit_alignment(tmpfp, 8);
2959         emit_label(tmpfp, symbol);
2960         fprintf (tmpfp, ".long %d\n", acfg->image_table->len);
2961         for (i = 0; i < acfg->image_table->len; i++) {
2962                 MonoImage *image = (MonoImage*)g_ptr_array_index (acfg->image_table, i);
2963                 MonoAssemblyName *aname = &image->assembly->aname;
2964
2965                 /* FIXME: Support multi-module assemblies */
2966                 g_assert (image->assembly->image == image);
2967
2968                 fprintf (tmpfp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, image->assembly_name);
2969                 fprintf (tmpfp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, image->guid);
2970                 fprintf (tmpfp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, aname->culture ? aname->culture : "");
2971                 fprintf (tmpfp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, aname->public_key_token);
2972
2973                 emit_alignment (tmpfp, 8);
2974                 fprintf (tmpfp, ".long %d\n", aname->flags);
2975                 fprintf (tmpfp, ".long %d\n", aname->major);
2976                 fprintf (tmpfp, ".long %d\n", aname->minor);
2977                 fprintf (tmpfp, ".long %d\n", aname->build);
2978                 fprintf (tmpfp, ".long %d\n", aname->revision);
2979         }
2980
2981 #ifdef MONO_ARCH_HAVE_PIC_AOT
2982         /* Emit GOT */
2983
2984         /* Don't make GOT global so accesses to it don't need relocations */
2985         symbol = g_strdup_printf ("got");
2986         emit_section_change (tmpfp, ".bss", 1);
2987         emit_alignment (tmpfp, 8);
2988         emit_label(tmpfp, symbol);
2989         if (acfg->got_offset > 0)
2990                 fprintf (tmpfp, ".skip %d\n", (int)(acfg->got_offset * sizeof (gpointer)));
2991
2992         printf ("Code: %d Info: %d Ex Info: %d Class Info: %d GOT: %d\n", acfg->code_size, acfg->info_size, acfg->ex_info_size, acfg->class_info_size, (int)(acfg->got_offset * sizeof (gpointer)));
2993
2994         symbol = g_strdup_printf ("got_addr");
2995         emit_section_change (tmpfp, ".data", 1);
2996         emit_global (tmpfp, symbol, FALSE);
2997         emit_alignment (tmpfp, 8);
2998         emit_label(tmpfp, symbol);
2999         emit_pointer (tmpfp, "got");
3000
3001         symbol = g_strdup_printf ("got_size");
3002         emit_section_change (tmpfp, ".data", 1);
3003         emit_global (tmpfp, symbol, FALSE);
3004         emit_alignment (tmpfp, 8);
3005         emit_label(tmpfp, symbol);
3006         fprintf (tmpfp, ".long %d\n", (int)(acfg->got_offset * sizeof (gpointer)));
3007 #endif
3008
3009         symbol = g_strdup_printf ("mem_end");
3010         emit_section_change (tmpfp, ".text", 1);
3011         emit_global (tmpfp, symbol, FALSE);
3012         emit_alignment (tmpfp, 8);
3013         emit_label(tmpfp, symbol);
3014
3015         fclose (tmpfp);
3016
3017 #if defined(__x86_64__)
3018         com = g_strdup_printf ("as --64 %s -o %s.o", tmpfname, tmpfname);
3019 #elif defined(sparc) && SIZEOF_VOID_P == 8
3020         com = g_strdup_printf ("as -xarch=v9 %s -o %s.o", tmpfname, tmpfname);
3021 #else
3022         com = g_strdup_printf ("as %s -o %s.o", tmpfname, tmpfname);
3023         
3024 #endif
3025         printf ("Executing the native assembler: %s\n", com);
3026         if (system (com) != 0) {
3027                 g_free (com);
3028                 return 1;
3029         }
3030
3031         g_free (com);
3032
3033         if (acfg->aot_opts.outfile)
3034                 outfile_name = g_strdup_printf ("%s", acfg->aot_opts.outfile);
3035         else
3036                 outfile_name = g_strdup_printf ("%s%s", image->name, SHARED_EXT);
3037
3038         tmp_outfile_name = g_strdup_printf ("%s.tmp", outfile_name);
3039
3040 #if defined(sparc)
3041         com = g_strdup_printf ("ld -shared -G -o %s %s.o", outfile_name, tmpfname);
3042 #elif defined(__ppc__) && defined(__MACH__)
3043         com = g_strdup_printf ("gcc -dynamiclib -o %s %s.o", outfile_name, tmpfname);
3044 #elif defined(PLATFORM_WIN32)
3045         com = g_strdup_printf ("gcc -shared --dll -mno-cygwin -o %s %s.o", outfile_name, tmpfname);
3046 #else
3047         com = g_strdup_printf ("ld -shared -o %s %s.o", outfile_name, tmpfname);
3048 #endif
3049         printf ("Executing the native linker: %s\n", com);
3050         if (system (com) != 0) {
3051                 g_free (tmp_outfile_name);
3052                 g_free (outfile_name);
3053                 g_free (com);
3054                 return 1;
3055         }
3056
3057         g_free (com);
3058         com = g_strdup_printf ("%s.o", tmpfname);
3059         unlink (com);
3060         g_free (com);
3061         /*com = g_strdup_printf ("strip --strip-unneeded %s%s", image->name, SHARED_EXT);
3062         printf ("Stripping the binary: %s\n", com);
3063         system (com);
3064         g_free (com);*/
3065
3066         rename (tmp_outfile_name, outfile_name);
3067
3068         g_free (tmp_outfile_name);
3069         g_free (outfile_name);
3070
3071         printf ("Compiled %d out of %d methods (%d%%)\n", acfg->ccount, acfg->mcount, acfg->mcount ? (acfg->ccount*100)/acfg->mcount : 100);
3072         printf ("%d methods contain absolute addresses (%d%%)\n", acfg->abscount, acfg->mcount ? (acfg->abscount*100)/acfg->mcount : 100);
3073         printf ("%d methods contain wrapper references (%d%%)\n", acfg->wrappercount, acfg->mcount ? (acfg->wrappercount*100)/acfg->mcount : 100);
3074         printf ("%d methods contain lmf pointers (%d%%)\n", acfg->lmfcount, acfg->mcount ? (acfg->lmfcount*100)/acfg->mcount : 100);
3075         printf ("%d methods have other problems (%d%%)\n", acfg->ocount, acfg->mcount ? (acfg->ocount*100)/acfg->mcount : 100);
3076         if (acfg->aot_opts.save_temps)
3077                 printf ("Retained input file.\n");
3078         else
3079                 unlink (tmpfname);
3080
3081         return 0;
3082 }
3083
3084 #else
3085 /* AOT disabled */
3086
3087 void
3088 mono_aot_init (void)
3089 {
3090 }
3091
3092 MonoJitInfo*
3093 mono_aot_get_method (MonoDomain *domain, MonoMethod *method)
3094 {
3095         return NULL;
3096 }
3097
3098 gboolean
3099 mono_aot_is_got_entry (guint8 *code, guint8 *addr)
3100 {
3101         return FALSE;
3102 }
3103
3104 int
3105 mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
3106 {
3107         return 0;
3108 }
3109
3110 gboolean
3111 mono_aot_init_vtable (MonoVTable *vtable)
3112 {
3113         return FALSE;
3114 }
3115
3116 gboolean
3117 mono_aot_get_cached_class_info (MonoClass *klass, MonoCachedClassInfo *res)
3118 {
3119         return FALSE;
3120 }
3121
3122 MonoJitInfo *
3123 mono_aot_find_jit_info (MonoDomain *domain, MonoImage *image, gpointer addr)
3124 {
3125         return NULL;
3126 }
3127
3128 gpointer
3129 mono_aot_get_method_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
3130 {
3131         return NULL;
3132 }
3133
3134 gboolean
3135 mono_aot_is_pagefault (void *ptr)
3136 {
3137         return FALSE;
3138 }
3139
3140 void
3141 mono_aot_set_make_unreadable (gboolean unreadable)
3142 {
3143 }
3144
3145 guint32
3146 mono_aot_get_n_pagefaults (void)
3147 {
3148         return 0;
3149 }
3150
3151 void
3152 mono_aot_handle_pagefault (void *ptr)
3153 {
3154 }
3155
3156 #endif