2008-09-27 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / aot-runtime.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 #ifdef HAVE_UNISTD_H
14 #include <unistd.h>
15 #endif
16 #include <fcntl.h>
17 #include <string.h>
18 #ifndef PLATFORM_WIN32
19 #include <sys/mman.h>
20 #else
21 #include <winsock2.h>
22 #include <windows.h>
23 #endif
24
25 #ifdef HAVE_EXECINFO_H
26 #include <execinfo.h>
27 #endif
28
29 #include <errno.h>
30 #include <sys/stat.h>
31 #include <limits.h>    /* for PAGESIZE */
32 #ifndef PAGESIZE
33 #define PAGESIZE 4096
34 #endif
35
36 #ifdef HAVE_SYS_WAIT_H
37 #include <sys/wait.h>  /* for WIFEXITED, WEXITSTATUS */
38 #endif
39
40 #include <mono/metadata/tabledefs.h>
41 #include <mono/metadata/class.h>
42 #include <mono/metadata/object.h>
43 #include <mono/metadata/tokentype.h>
44 #include <mono/metadata/appdomain.h>
45 #include <mono/metadata/debug-helpers.h>
46 #include <mono/metadata/assembly.h>
47 #include <mono/metadata/metadata-internals.h>
48 #include <mono/metadata/marshal.h>
49 #include <mono/metadata/gc-internal.h>
50 #include <mono/utils/mono-logger.h>
51 #include "mono/utils/mono-compiler.h"
52
53 #include "mini.h"
54 #include "version.h"
55
56 #ifndef DISABLE_AOT
57
58 #ifdef PLATFORM_WIN32
59 #define SHARED_EXT ".dll"
60 #elif (defined(__ppc__) || defined(__powerpc__) || defined(__ppc64__)) || defined(__MACH__)
61 #define SHARED_EXT ".dylib"
62 #else
63 #define SHARED_EXT ".so"
64 #endif
65
66 #define ALIGN_PTR_TO(ptr,align) (gpointer)((((gssize)(ptr)) + (align - 1)) & (~(align - 1)))
67 #define ROUND_DOWN(VALUE,SIZE)  ((VALUE) & ~((SIZE) - 1))
68
69 typedef struct MonoAotModule {
70         char *aot_name;
71         /* Optimization flags used to compile the module */
72         guint32 opts;
73         /* Pointer to the Global Offset Table */
74         gpointer *got;
75         guint32 got_size;
76         GHashTable *name_cache;
77         GHashTable *wrappers;
78         /* Maps wrapper names to their method index */
79         GHashTable *wrappers_by_name;
80         /* Maps wrapper methods to their code */
81         GHashTable *wrappers_to_code;
82         MonoAssemblyName *image_names;
83         char **image_guids;
84         MonoAssembly *assembly;
85         MonoImage **image_table;
86         guint32 image_table_len;
87         gboolean out_of_date;
88         gboolean plt_inited;
89         guint8 *mem_begin;
90         guint8 *mem_end;
91         guint8 *code;
92         guint8 *code_end;
93         guint8 *plt;
94         guint8 *plt_end;
95         guint8 *plt_info;
96         guint8 *plt_jump_table;
97         guint32 plt_jump_table_size;
98         guint32 *code_offsets;
99         guint8 *method_info;
100         guint32 *method_info_offsets;
101         guint8 *got_info;
102         guint32 *got_info_offsets;
103         guint8 *ex_info;
104         guint32 *ex_info_offsets;
105         guint32 *method_order;
106         guint32 *method_order_end;
107         guint8 *class_info;
108         guint32 *class_info_offsets;
109         guint32 *methods_loaded;
110         guint16 *class_name_table;
111         guint8 *wrapper_info;
112         guint8 *trampolines;
113         guint32 num_trampolines, first_trampoline_got_offset, trampoline_index;
114         gpointer *globals;
115         MonoDl *sofile;
116 } MonoAotModule;
117
118 static GHashTable *aot_modules;
119 #define mono_aot_lock() EnterCriticalSection (&aot_mutex)
120 #define mono_aot_unlock() LeaveCriticalSection (&aot_mutex)
121 static CRITICAL_SECTION aot_mutex;
122
123 /* 
124  * Maps assembly names to the mono_aot_module_<NAME>_info symbols in the
125  * AOT modules registered by mono_aot_register_module ().
126  */
127 static GHashTable *static_aot_modules;
128
129 /*
130  * Disabling this will make a copy of the loaded code and use the copy instead 
131  * of the original. This will place the caller and the callee close to each 
132  * other in memory, possibly improving cache behavior. Since the original
133  * code is in copy-on-write memory, this will not increase the memory usage
134  * of the runtime.
135  */
136 static gboolean use_loaded_code = TRUE;
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 /*
145  * Whenever to spawn a new process to AOT a file or do it in-process. Only relevant if
146  * use_aot_cache is TRUE.
147  */
148 static gboolean spawn_compiler = TRUE;
149
150 /* For debugging */
151 static gint32 mono_last_aot_method = -1;
152
153 static gboolean make_unreadable = FALSE;
154 static guint32 n_pagefaults = 0;
155 static guint32 name_table_accesses = 0;
156
157 /* Used to speed-up find_aot_module () */
158 static gsize aot_code_low_addr = (gssize)-1;
159 static gsize aot_code_high_addr = 0;
160
161 /* Used to communicate with mono_aot_register_globals () */
162 static guint32 globals_tls_id = -1;
163
164 static gpointer
165 mono_aot_load_method (MonoDomain *domain, MonoAotModule *aot_module, MonoMethod *method, guint8 *code, guint8 *info, int method_index);
166
167 static void
168 init_plt (MonoAotModule *info);
169
170 static MonoJumpInfo*
171 load_patch_info (MonoAotModule *aot_module, MonoMemPool *mp, int n_patches, 
172                                  guint32 got_index, guint32 **got_slots, 
173                                  guint8 *buf, guint8 **endbuf);
174
175 static inline gboolean 
176 is_got_patch (MonoJumpInfoType patch_type)
177 {
178         return TRUE;
179 }
180
181 /*****************************************************/
182 /*                 AOT RUNTIME                       */
183 /*****************************************************/
184
185 static MonoImage *
186 load_image (MonoAotModule *module, int index)
187 {
188         MonoAssembly *assembly;
189         MonoImageOpenStatus status;
190
191         g_assert (index < module->image_table_len);
192
193         if (module->image_table [index])
194                 return module->image_table [index];
195         if (module->out_of_date)
196                 return NULL;
197
198         assembly = mono_assembly_load (&module->image_names [index], NULL, &status);
199         if (!assembly) {
200                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT module %s is unusable because dependency %s is not found.\n", module->aot_name, module->image_names [index].name);
201                 module->out_of_date = TRUE;
202                 return NULL;
203         }
204
205         if (strcmp (assembly->image->guid, module->image_guids [index])) {
206                 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);
207                 module->out_of_date = TRUE;
208                 return NULL;
209         }
210
211         module->image_table [index] = assembly->image;
212         return assembly->image;
213 }
214
215
216 static inline gint32
217 decode_value (guint8 *ptr, guint8 **rptr)
218 {
219         guint8 b = *ptr;
220         gint32 len;
221         
222         if ((b & 0x80) == 0){
223                 len = b;
224                 ++ptr;
225         } else if ((b & 0x40) == 0){
226                 len = ((b & 0x3f) << 8 | ptr [1]);
227                 ptr += 2;
228         } else if (b != 0xff) {
229                 len = ((b & 0x1f) << 24) |
230                         (ptr [1] << 16) |
231                         (ptr [2] << 8) |
232                         ptr [3];
233                 ptr += 4;
234         }
235         else {
236                 len = (ptr [1] << 24) | (ptr [2] << 16) | (ptr [3] << 8) | ptr [4];
237                 ptr += 5;
238         }
239         if (rptr)
240                 *rptr = ptr;
241
242         //printf ("DECODE: %d.\n", len);
243         return len;
244 }
245
246 static MonoMethod*
247 decode_method_ref_2 (MonoAotModule *module, guint8 *buf, guint8 **endbuf);
248
249 static MonoClass*
250 decode_klass_ref (MonoAotModule *module, guint8 *buf, guint8 **endbuf);
251
252 static MonoGenericInst*
253 decode_generic_inst (MonoAotModule *module, guint8 *buf, guint8 **endbuf)
254 {
255         int type_argc, i;
256         MonoType **type_argv;
257         MonoGenericInst *inst;
258         guint8 *p = buf;
259
260         type_argc = decode_value (p, &p);
261         type_argv = g_new0 (MonoType*, type_argc);
262
263         for (i = 0; i < type_argc; ++i) {
264                 MonoClass *pclass = decode_klass_ref (module, p, &p);
265                 if (!pclass) {
266                         g_free (type_argv);
267                         return NULL;
268                 }
269                 type_argv [i] = &pclass->byval_arg;
270         }
271
272         inst = mono_metadata_get_generic_inst (type_argc, type_argv);
273         g_free (type_argv);
274
275         *endbuf = p;
276
277         return inst;
278 }
279
280 static MonoClass*
281 decode_klass_ref (MonoAotModule *module, guint8 *buf, guint8 **endbuf)
282 {
283         MonoImage *image;
284         MonoClass *klass, *eklass;
285         guint32 token, rank;
286         guint8 *p = buf;
287
288         token = decode_value (p, &p);
289         if (token == 0) {
290                 *endbuf = p;
291                 return NULL;
292         }
293         if (mono_metadata_token_table (token) == 0) {
294                 image = load_image (module, decode_value (p, &p));
295                 if (!image)
296                         return NULL;
297                 klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF + token);
298         } else if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC) {
299                 if (token == MONO_TOKEN_TYPE_SPEC) {
300                         MonoTypeEnum type = decode_value (p, &p);
301
302                         if (type == MONO_TYPE_GENERICINST) {
303                                 MonoClass *gclass;
304                                 MonoGenericContext ctx;
305                                 MonoType *type;
306
307                                 gclass = decode_klass_ref (module, p, &p);
308                                 g_assert (gclass->generic_container);
309
310                                 memset (&ctx, 0, sizeof (ctx));
311                                 ctx.class_inst = decode_generic_inst (module, p, &p);
312                                 if (!ctx.class_inst)
313                                         return NULL;
314                                 type = mono_class_inflate_generic_type (&gclass->byval_arg, &ctx);
315                                 klass = mono_class_from_mono_type (type);
316                                 mono_metadata_free_type (type);
317                         } else if ((type == MONO_TYPE_VAR) || (type == MONO_TYPE_MVAR)) {
318                                 MonoType *t;
319                                 gboolean is_method;
320                                 MonoGenericContainer *container;
321
322                                 // FIXME: Maybe use types directly to avoid
323                                 // the overhead of creating MonoClass-es
324
325                                 // FIXME: Memory management
326                                 t = g_new0 (MonoType, 1);
327                                 t->type = type;
328                                 t->data.generic_param = g_new0 (MonoGenericParam, 1);
329                                 t->data.generic_param->num = decode_value (p, &p);
330                                 t->data.generic_param->name = "T";
331
332                                 is_method = decode_value (p, &p);
333                                 if (is_method) {
334                                         MonoMethod *method_def = decode_method_ref_2 (module, p, &p);
335
336                                         if (!method_def) {
337                                                 g_free (t->data.generic_param);
338                                                 g_free (t);
339                                                 return NULL;
340                                         }
341
342                                         container = mono_method_get_generic_container (method_def);
343                                 } else {
344                                         MonoClass *class_def = decode_klass_ref (module, p, &p);
345                                         
346                                         if (!class_def) {
347                                                 g_free (t->data.generic_param);
348                                                 g_free (t);
349                                                 return NULL;
350                                         }
351
352                                         container = class_def->generic_container;
353                                 }
354
355                                 g_assert (container);
356                                 t->data.generic_param->owner = container;
357
358                                 klass = mono_class_from_mono_type (t);
359                         } else {
360                                 g_assert_not_reached ();
361                         }
362                 } else {
363                         image = load_image (module, decode_value (p, &p));
364                         if (!image)
365                                 return NULL;
366                         klass = mono_class_get (image, token);
367                 }
368         } else if (token == MONO_TOKEN_TYPE_DEF) {
369                 /* Array */
370                 image = load_image (module, decode_value (p, &p));
371                 if (!image)
372                         return NULL;
373                 rank = decode_value (p, &p);
374                 eklass = decode_klass_ref (module, p, &p);
375                 klass = mono_array_class_get (eklass, rank);
376         } else {
377                 g_assert_not_reached ();
378         }
379         g_assert (klass);
380         mono_class_init (klass);
381
382         *endbuf = p;
383         return klass;
384 }
385
386 static MonoClassField*
387 decode_field_info (MonoAotModule *module, guint8 *buf, guint8 **endbuf)
388 {
389         MonoClass *klass = decode_klass_ref (module, buf, &buf);
390         guint32 token;
391         guint8 *p = buf;
392
393         if (!klass)
394                 return NULL;
395
396         token = MONO_TOKEN_FIELD_DEF + decode_value (p, &p);
397
398         *endbuf = p;
399
400         return mono_class_get_field (klass, token);
401 }
402
403 /*
404  * decode_method_ref:
405  *
406  *   Decode a method reference, and return its image and token. This avoids loading
407  * metadata for the method if the caller does not need it. If the method has no token,
408  * then it is loaded from metadata and METHOD is set to the method instance.
409  */
410 static inline MonoImage*
411 decode_method_ref (MonoAotModule *module, guint32 *token, MonoMethod **method, guint8 *buf, guint8 **endbuf)
412 {
413         guint32 image_index, value;
414         MonoImage *image;
415         guint8 *p = buf;
416
417         if (method)
418                 *method = NULL;
419
420         value = decode_value (p, &p);
421         image_index = value >> 24;
422
423         if (image_index == 253) {
424                 /* Wrapper */
425                 guint32 wrapper_type;
426
427                 wrapper_type = decode_value (p, &p);
428
429                 /* Doesn't matter */
430                 image = mono_defaults.corlib;
431
432                 switch (wrapper_type) {
433                 case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK: {
434                         MonoMethod *m = decode_method_ref_2 (module, p, &p);
435
436                         if (!m)
437                                 return NULL;
438                         mono_class_init (m->klass);
439                         *method = mono_marshal_get_remoting_invoke_with_check (m);
440                         break;
441                 }
442                 case MONO_WRAPPER_PROXY_ISINST: {
443                         MonoClass *klass = decode_klass_ref (module, p, &p);
444                         if (!klass)
445                                 return NULL;
446                         *method = mono_marshal_get_proxy_cancast (klass);
447                         break;
448                 }
449                 case MONO_WRAPPER_LDFLD:
450                 case MONO_WRAPPER_LDFLDA:
451                 case MONO_WRAPPER_STFLD:
452                 case MONO_WRAPPER_ISINST: {
453                         MonoClass *klass = decode_klass_ref (module, p, &p);
454                         if (!klass)
455                                 return NULL;
456                         if (wrapper_type == MONO_WRAPPER_LDFLD)
457                                 *method = mono_marshal_get_ldfld_wrapper (&klass->byval_arg);
458                         else if (wrapper_type == MONO_WRAPPER_LDFLDA)
459                                 *method = mono_marshal_get_ldflda_wrapper (&klass->byval_arg);
460                         else if (wrapper_type == MONO_WRAPPER_STFLD)
461                                 *method = mono_marshal_get_stfld_wrapper (&klass->byval_arg);
462                         else if (wrapper_type == MONO_WRAPPER_ISINST)
463                                 *method = mono_marshal_get_isinst (klass);
464                         else
465                                 g_assert_not_reached ();
466                         break;
467                 }
468                 case MONO_WRAPPER_LDFLD_REMOTE:
469                         *method = mono_marshal_get_ldfld_remote_wrapper (NULL);
470                         break;
471                 case MONO_WRAPPER_STFLD_REMOTE:
472                         *method = mono_marshal_get_stfld_remote_wrapper (NULL);
473                         break;
474                 case MONO_WRAPPER_ALLOC: {
475                         int atype = decode_value (p, &p);
476
477                         *method = mono_gc_get_managed_allocator_by_type (atype);
478                         break;
479                 }
480                 case MONO_WRAPPER_STELEMREF:
481                         *method = mono_marshal_get_stelemref ();
482                         break;
483                 case MONO_WRAPPER_STATIC_RGCTX_INVOKE: {
484                         MonoMethod *m = decode_method_ref_2 (module, p, &p);
485
486                         if (!m)
487                                 return NULL;
488                         *method = mono_marshal_get_static_rgctx_invoke (m);
489                         break;
490                 }
491                 default:
492                         g_assert_not_reached ();
493                 }
494         } else if (image_index == 255) {
495                 /* Methodspec */
496                 image_index = decode_value (p, &p);
497                 *token = decode_value (p, &p);
498
499                 image = load_image (module, image_index);
500                 if (!image)
501                         return NULL;
502         } else if (image_index == 254) {
503                 /* Method on generic instance */
504                 MonoClass *klass;
505                 MonoGenericContext ctx;
506                 gboolean has_class_inst, has_method_inst;
507
508                 /* 
509                  * These methods do not have a token which resolves them, so we 
510                  * resolve them immediately.
511                  */
512                 klass = decode_klass_ref (module, p, &p);
513                 if (!klass)
514                         return NULL;
515
516                 image_index = decode_value (p, &p);
517                 *token = decode_value (p, &p);
518
519                 image = load_image (module, image_index);
520                 if (!image)
521                         return NULL;
522
523                 *method = mono_get_method_full (image, *token, NULL, NULL);
524                 if (!(*method))
525                         return NULL;
526
527                 memset (&ctx, 0, sizeof (ctx));
528
529                 if (FALSE && klass->generic_class) {
530                         ctx.class_inst = klass->generic_class->context.class_inst;
531                         ctx.method_inst = NULL;
532  
533                         *method = mono_class_inflate_generic_method_full (*method, klass, &ctx);
534                 }                       
535
536                 memset (&ctx, 0, sizeof (ctx));
537
538                 // FIXME: Memory management
539                 has_class_inst = decode_value (p, &p);
540                 if (has_class_inst) {
541                         ctx.class_inst = decode_generic_inst (module, p, &p);
542                         if (!ctx.class_inst)
543                                 return NULL;
544                 }
545                 has_method_inst = decode_value (p, &p);
546                 if (has_method_inst) {
547                         ctx.method_inst = decode_generic_inst (module, p, &p);
548                         if (!ctx.method_inst)
549                                 return NULL;
550                 }
551
552                 *method = mono_class_inflate_generic_method_full (*method, klass, &ctx);
553         } else {
554                 *token = MONO_TOKEN_METHOD_DEF | (value & 0xffffff);
555
556                 image = load_image (module, image_index);
557                 if (!image)
558                         return NULL;
559         }
560
561         *endbuf = p;
562
563         return image;
564 }
565
566 /*
567  * decode_method_ref_2:
568  *
569  *   Similar to decode_method_ref, but resolve and return the method itself.
570  */
571 static MonoMethod*
572 decode_method_ref_2 (MonoAotModule *module, guint8 *buf, guint8 **endbuf)
573 {
574         MonoMethod *method;
575         guint32 token;
576         MonoImage *image = decode_method_ref (module, &token, &method, buf, endbuf);
577
578         if (method)
579                 return method;
580         if (!image)
581                 return NULL;
582         return mono_get_method (image, token, NULL);
583 }
584
585 G_GNUC_UNUSED
586 static void
587 make_writable (guint8* addr, guint32 len)
588 {
589 #ifndef PLATFORM_WIN32
590         guint8 *page_start;
591         int pages, err;
592
593         if (mono_aot_only)
594                 g_error ("Attempt to make AOT memory writable while running in aot-only mode.\n");
595
596         page_start = (guint8 *) (((gssize) (addr)) & ~ (PAGESIZE - 1));
597         pages = (addr + len - page_start + PAGESIZE - 1) / PAGESIZE;
598         err = mprotect (page_start, pages * PAGESIZE, PROT_READ | PROT_WRITE | PROT_EXEC);
599         g_assert (err == 0);
600 #else
601         {
602                 DWORD oldp;
603                 g_assert (VirtualProtect (addr, len, PAGE_EXECUTE_READWRITE, &oldp) != 0);
604         }
605 #endif
606 }
607
608 static void
609 create_cache_structure (void)
610 {
611         const char *home;
612         char *tmp;
613         int err;
614
615         home = g_get_home_dir ();
616         if (!home)
617                 return;
618
619         tmp = g_build_filename (home, ".mono", NULL);
620         if (!g_file_test (tmp, G_FILE_TEST_IS_DIR)) {
621                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT creating directory %s", tmp);
622 #ifdef PLATFORM_WIN32
623                 err = mkdir (tmp);
624 #else
625                 err = mkdir (tmp, 0777);
626 #endif
627                 if (err) {
628                         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT failed: %s", g_strerror (errno));
629                         g_free (tmp);
630                         return;
631                 }
632         }
633         g_free (tmp);
634         tmp = g_build_filename (home, ".mono", "aot-cache", NULL);
635         if (!g_file_test (tmp, G_FILE_TEST_IS_DIR)) {
636                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT creating directory %s", tmp);
637 #ifdef PLATFORM_WIN32
638                 err = mkdir (tmp);
639 #else
640                 err = mkdir (tmp, 0777);
641 #endif
642                 if (err) {
643                         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT failed: %s", g_strerror (errno));
644                         g_free (tmp);
645                         return;
646                 }
647         }
648         g_free (tmp);
649 }
650
651 /*
652  * load_aot_module_from_cache:
653  *
654  *  Experimental code to AOT compile loaded assemblies on demand. 
655  *
656  * FIXME: 
657  * - Add environment variable MONO_AOT_CACHE_OPTIONS
658  * - Add options for controlling the cache size
659  * - Handle full cache by deleting old assemblies lru style
660  * - Add options for excluding assemblies during development
661  * - Maybe add a threshold after an assembly is AOT compiled
662  * - invoking a new mono process is a security risk
663  * - recompile the AOT module if one of its dependencies changes
664  */
665 static MonoDl*
666 load_aot_module_from_cache (MonoAssembly *assembly, char **aot_name)
667 {
668         char *fname, *cmd, *tmp2, *aot_options;
669         const char *home;
670         MonoDl *module;
671         gboolean res;
672         gchar *out, *err;
673         gint exit_status;
674
675         *aot_name = NULL;
676
677         if (assembly->image->dynamic)
678                 return NULL;
679
680         create_cache_structure ();
681
682         home = g_get_home_dir ();
683
684         tmp2 = g_strdup_printf ("%s-%s%s", assembly->image->assembly_name, assembly->image->guid, SHARED_EXT);
685         fname = g_build_filename (home, ".mono", "aot-cache", tmp2, NULL);
686         *aot_name = fname;
687         g_free (tmp2);
688
689         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT trying to load from cache: '%s'.", fname);
690         module = mono_dl_open (fname, MONO_DL_LAZY, NULL);
691
692         if (!module) {
693                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT not found.");
694
695                 mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT precompiling assembly '%s'... ", assembly->image->name);
696
697                 aot_options = g_strdup_printf ("outfile=%s", fname);
698
699                 if (spawn_compiler) {
700                         /* FIXME: security */
701                         /* FIXME: Has to pass the assembly loading path to the child process */
702                         cmd = g_strdup_printf ("mono -O=all --aot=%s %s", aot_options, assembly->image->name);
703
704                         res = g_spawn_command_line_sync (cmd, &out, &err, &exit_status, NULL);
705
706 #if !defined(PLATFORM_WIN32) && !defined(__ppc__) && !defined(__ppc64__) && !defined(__powerpc__)
707                         if (res) {
708                                 if (!WIFEXITED (exit_status) && (WEXITSTATUS (exit_status) == 0))
709                                         mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT failed: %s.", err);
710                                 else
711                                         mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT succeeded.");
712                                 g_free (out);
713                                 g_free (err);
714                         }
715 #endif
716                         g_free (cmd);
717                 } else {
718                         res = mono_compile_assembly (assembly, mono_parse_default_optimizations (NULL), aot_options);
719                         if (!res) {
720                                 mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT failed.");
721                         } else {
722                                 mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT succeeded.");
723                         }
724                 }
725
726                 module = mono_dl_open (fname, MONO_DL_LAZY, NULL);
727
728                 g_free (aot_options);
729         }
730
731         return module;
732 }
733
734 static void
735 find_symbol (MonoDl *module, gpointer *globals, const char *name, gpointer *value)
736 {
737         if (globals) {
738                 int i = 0;
739
740                 *value = NULL;
741                 for (i = 0; globals [i]; i+= 2) {
742                         if (strcmp (globals [i], name) == 0) {
743                                 *value = globals [i + 1];
744                                 break;
745                         }
746                 }
747         } else {
748                 mono_dl_symbol (module, name, value);
749         }
750 }
751
752 static void
753 load_aot_module (MonoAssembly *assembly, gpointer user_data)
754 {
755         char *aot_name;
756         MonoAotModule *amodule;
757         MonoDl *sofile;
758         gboolean usable = TRUE;
759         char *saved_guid = NULL;
760         char *aot_version = NULL;
761         char *runtime_version;
762         char *opt_flags = NULL;
763         gpointer *globals;
764         gboolean full_aot = FALSE;
765         gpointer *plt_jump_table_addr = NULL;
766         guint32 *plt_jump_table_size = NULL;
767         guint32 *trampolines_info = NULL;
768         gpointer *got_addr = NULL;
769         gpointer *got = NULL;
770         guint32 *got_size_ptr = NULL;
771         int i;
772
773         if (mono_compile_aot)
774                 return;
775
776         if (assembly->image->aot_module)
777                 /* 
778                  * Already loaded. This can happen because the assembly loading code might invoke
779                  * the assembly load hooks multiple times for the same assembly.
780                  */
781                 return;
782
783         if (assembly->image->dynamic)
784                 return;
785
786         mono_aot_lock ();
787         if (static_aot_modules)
788                 globals = g_hash_table_lookup (static_aot_modules, assembly->aname.name);
789         else
790                 globals = NULL;
791         mono_aot_unlock ();
792
793         if (globals) {
794                 /* Statically linked AOT module */
795                 sofile = NULL;
796                 aot_name = g_strdup_printf ("%s", assembly->aname.name);
797                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "Found statically linked AOT module '%s'.\n", aot_name);
798         } else {
799                 TlsSetValue (globals_tls_id, NULL);
800
801                 if (use_aot_cache)
802                         sofile = load_aot_module_from_cache (assembly, &aot_name);
803                 else {
804                         char *err;
805                         aot_name = g_strdup_printf ("%s%s", assembly->image->name, SHARED_EXT);
806
807                         sofile = mono_dl_open (aot_name, MONO_DL_LAZY, &err);
808
809                         if (!sofile) {
810                                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT failed to load AOT module %s: %s\n", aot_name, err);
811                                 g_free (err);
812                         }
813                 }
814
815                 /*
816                  * If the image was compiled in no-dlsym mode, it contains no global symbols,
817                  * instead it contains an ELF ctor function which is called by dlopen () which 
818                  * in turn calls mono_aot_register_globals () to register a table which contains
819                  * the name and address of the globals.
820                  */
821                 globals = TlsGetValue (globals_tls_id);
822                 TlsSetValue (globals_tls_id, NULL);
823         }
824
825         if (!sofile && !globals) {
826                 if (mono_aot_only) {
827                         fprintf (stderr, "Failed to load AOT module '%s' in aot-only mode.\n", aot_name);
828                         exit (1);
829                 }
830                 g_free (aot_name);
831                 return;
832         }
833
834         find_symbol (sofile, globals, "mono_assembly_guid", (gpointer *) &saved_guid);
835         find_symbol (sofile, globals, "mono_aot_version", (gpointer *) &aot_version);
836         find_symbol (sofile, globals, "mono_aot_opt_flags", (gpointer *)&opt_flags);
837         find_symbol (sofile, globals, "mono_runtime_version", (gpointer *)&runtime_version);
838
839         if (!aot_version || strcmp (aot_version, MONO_AOT_FILE_VERSION)) {
840                 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);
841                 usable = FALSE;
842         }
843         else {
844                 if (!saved_guid || strcmp (assembly->image->guid, saved_guid)) {
845                         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT module %s is out of date.\n", aot_name);
846                         usable = FALSE;
847                 }
848         }
849
850         if (!runtime_version || ((strlen (runtime_version) > 0 && strcmp (runtime_version, FULL_VERSION)))) {
851                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT module %s is compiled against runtime version %s while this runtime has version %s.\n", aot_name, runtime_version, FULL_VERSION);
852                 usable = FALSE;
853         }
854
855         {
856                 char *full_aot_str;
857
858                 find_symbol (sofile, globals, "mono_aot_full_aot", (gpointer *)&full_aot_str);
859
860                 if (full_aot_str && !strcmp (full_aot_str, "TRUE"))
861                         full_aot = TRUE;
862         }
863
864         if (mono_aot_only && !full_aot) {
865                 fprintf (stderr, "Can't use AOT image '%s' in aot-only mode because it is not compiled with --aot=full.\n", aot_name);
866                 exit (1);
867         }
868         if (!mono_aot_only && full_aot) {
869                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT module %s is compiled with --aot=full.\n", aot_name);
870                 usable = FALSE;
871         }
872
873         if (!usable) {
874                 if (mono_aot_only) {
875                         fprintf (stderr, "Failed to load AOT module '%s' while running in aot-only mode.\n", aot_name);
876                         exit (1);
877                 }
878                 g_free (aot_name);
879                 if (sofile)
880                         mono_dl_close (sofile);
881                 assembly->image->aot_module = NULL;
882                 return;
883         }
884
885         find_symbol (sofile, globals, "got_addr", (gpointer *)&got_addr);
886         g_assert (got_addr);
887         got = (gpointer*)*got_addr;
888         g_assert (got);
889         find_symbol (sofile, globals, "got_size", (gpointer *)&got_size_ptr);
890         g_assert (got_size_ptr);
891
892         amodule = g_new0 (MonoAotModule, 1);
893         amodule->aot_name = aot_name;
894         amodule->assembly = assembly;
895         amodule->got = got;
896         amodule->got_size = *got_size_ptr;
897         amodule->got [0] = assembly->image;
898         amodule->globals = globals;
899         amodule->sofile = sofile;
900
901         sscanf (opt_flags, "%d", &amodule->opts);               
902
903         /* Read image table */
904         {
905                 guint32 table_len, i;
906                 char *table = NULL;
907
908                 find_symbol (sofile, globals, "mono_image_table", (gpointer *)&table);
909                 g_assert (table);
910
911                 table_len = *(guint32*)table;
912                 table += sizeof (guint32);
913                 amodule->image_table = g_new0 (MonoImage*, table_len);
914                 amodule->image_names = g_new0 (MonoAssemblyName, table_len);
915                 amodule->image_guids = g_new0 (char*, table_len);
916                 amodule->image_table_len = table_len;
917                 for (i = 0; i < table_len; ++i) {
918                         MonoAssemblyName *aname = &(amodule->image_names [i]);
919
920                         aname->name = g_strdup (table);
921                         table += strlen (table) + 1;
922                         amodule->image_guids [i] = g_strdup (table);
923                         table += strlen (table) + 1;
924                         if (table [0] != 0)
925                                 aname->culture = g_strdup (table);
926                         table += strlen (table) + 1;
927                         memcpy (aname->public_key_token, table, strlen (table) + 1);
928                         table += strlen (table) + 1;                    
929
930                         table = ALIGN_PTR_TO (table, 8);
931                         aname->flags = *(guint32*)table;
932                         table += 4;
933                         aname->major = *(guint32*)table;
934                         table += 4;
935                         aname->minor = *(guint32*)table;
936                         table += 4;
937                         aname->build = *(guint32*)table;
938                         table += 4;
939                         aname->revision = *(guint32*)table;
940                         table += 4;
941                 }
942         }
943
944         /* Read method and method_info tables */
945         find_symbol (sofile, globals, "method_offsets", (gpointer*)&amodule->code_offsets);
946         find_symbol (sofile, globals, "methods", (gpointer*)&amodule->code);
947         find_symbol (sofile, globals, "methods_end", (gpointer*)&amodule->code_end);
948         find_symbol (sofile, globals, "method_info_offsets", (gpointer*)&amodule->method_info_offsets);
949         find_symbol (sofile, globals, "method_info", (gpointer*)&amodule->method_info);
950         find_symbol (sofile, globals, "ex_info_offsets", (gpointer*)&amodule->ex_info_offsets);
951         find_symbol (sofile, globals, "ex_info", (gpointer*)&amodule->ex_info);
952         find_symbol (sofile, globals, "method_order", (gpointer*)&amodule->method_order);
953         find_symbol (sofile, globals, "method_order_end", (gpointer*)&amodule->method_order_end);
954         find_symbol (sofile, globals, "class_info", (gpointer*)&amodule->class_info);
955         find_symbol (sofile, globals, "class_info_offsets", (gpointer*)&amodule->class_info_offsets);
956         find_symbol (sofile, globals, "class_name_table", (gpointer *)&amodule->class_name_table);
957         find_symbol (sofile, globals, "got_info", (gpointer*)&amodule->got_info);
958         find_symbol (sofile, globals, "got_info_offsets", (gpointer*)&amodule->got_info_offsets);
959         find_symbol (sofile, globals, "wrapper_info", (gpointer*)&amodule->wrapper_info);
960         find_symbol (sofile, globals, "trampolines", (gpointer*)&amodule->trampolines);
961         find_symbol (sofile, globals, "mem_end", (gpointer*)&amodule->mem_end);
962
963         amodule->mem_begin = amodule->code;
964
965         find_symbol (sofile, globals, "plt", (gpointer*)&amodule->plt);
966         find_symbol (sofile, globals, "plt_end", (gpointer*)&amodule->plt_end);
967         find_symbol (sofile, globals, "plt_info", (gpointer*)&amodule->plt_info);
968
969         find_symbol (sofile, globals, "plt_jump_table_addr", (gpointer *)&plt_jump_table_addr);
970         g_assert (plt_jump_table_addr);
971         amodule->plt_jump_table = (guint8*)*plt_jump_table_addr;
972         g_assert (amodule->plt_jump_table);
973
974         find_symbol (sofile, globals, "plt_jump_table_size", (gpointer *)&plt_jump_table_size);
975         g_assert (plt_jump_table_size);
976         amodule->plt_jump_table_size = *plt_jump_table_size;
977
978         find_symbol (sofile, globals, "trampolines_info", (gpointer *)&trampolines_info);
979         if (trampolines_info) {
980                 amodule->num_trampolines = trampolines_info [0];
981                 amodule->first_trampoline_got_offset = trampolines_info [1];
982         }       
983
984         if (make_unreadable) {
985 #ifndef PLATFORM_WIN32
986                 guint8 *addr;
987                 guint8 *page_start;
988                 int pages, err, len;
989
990                 addr = amodule->mem_begin;
991                 len = amodule->mem_end - amodule->mem_begin;
992
993                 /* Round down in both directions to avoid modifying data which is not ours */
994                 page_start = (guint8 *) (((gssize) (addr)) & ~ (PAGESIZE - 1)) + PAGESIZE;
995                 pages = ((addr + len - page_start + PAGESIZE - 1) / PAGESIZE) - 1;
996                 err = mprotect (page_start, pages * PAGESIZE, 0);
997                 g_assert (err == 0);
998 #endif
999         }
1000
1001         mono_aot_lock ();
1002
1003         aot_code_low_addr = MIN (aot_code_low_addr, (gsize)amodule->code);
1004         aot_code_high_addr = MAX (aot_code_high_addr, (gsize)amodule->code_end);
1005
1006         g_hash_table_insert (aot_modules, assembly, amodule);
1007         mono_aot_unlock ();
1008
1009         mono_jit_info_add_aot_module (assembly->image, amodule->code, amodule->code_end);
1010
1011         assembly->image->aot_module = amodule;
1012
1013         /*
1014          * Since we store methoddef and classdef tokens when referring to methods/classes in
1015          * referenced assemblies, we depend on the exact versions of the referenced assemblies.
1016          * MS calls this 'hard binding'. This means we have to load all referenced assemblies
1017          * non-lazily, since we can't handle out-of-date errors later.
1018          */
1019         for (i = 0; i < amodule->image_table_len; ++i)
1020                 load_image (amodule, i);
1021
1022         if (amodule->out_of_date) {
1023                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT Module %s is unusable because a dependency is out-of-date.\n", assembly->image->name);
1024                 if (mono_aot_only) {
1025                         fprintf (stderr, "Failed to load AOT module '%s' while running in aot-only mode because a dependency cannot be found or it is out of date.\n", aot_name);
1026                         exit (1);
1027                 }
1028         }
1029         else
1030                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT loaded AOT Module for %s.\n", assembly->image->name);
1031 }
1032
1033 /*
1034  * mono_aot_register_globals:
1035  *
1036  *   This is called by the ctor function in AOT images compiled with the
1037  * 'no-dlsym' option.
1038  */
1039 void
1040 mono_aot_register_globals (gpointer *globals)
1041 {
1042         TlsSetValue (globals_tls_id, globals);
1043 }
1044
1045 /*
1046  * mono_aot_register_module:
1047  *
1048  *   This should be called by embedding code to register AOT modules statically linked
1049  * into the executable. AOT_INFO should be the value of the 
1050  * 'mono_aot_module_<ASSEMBLY_NAME>_info' global symbol from the AOT module.
1051  */
1052 void
1053 mono_aot_register_module (gpointer *aot_info)
1054 {
1055         gpointer *globals;
1056         char *aname;
1057
1058         globals = aot_info;
1059         g_assert (globals);
1060
1061         /* Determine the assembly name */
1062         find_symbol (NULL, globals, "mono_aot_assembly_name", (gpointer*)&aname);
1063         g_assert (aname);
1064
1065         /* This could be called before startup */
1066         if (aot_modules)
1067                 mono_aot_lock ();
1068
1069         if (!static_aot_modules)
1070                 static_aot_modules = g_hash_table_new (g_str_hash, g_str_equal);
1071
1072         g_hash_table_insert (static_aot_modules, aname, globals);
1073
1074         if (aot_modules)
1075                 mono_aot_unlock ();
1076 }
1077
1078 void
1079 mono_aot_init (void)
1080 {
1081         InitializeCriticalSection (&aot_mutex);
1082         aot_modules = g_hash_table_new (NULL, NULL);
1083         globals_tls_id = TlsAlloc ();
1084
1085         mono_install_assembly_load_hook (load_aot_module, NULL);
1086
1087         if (getenv ("MONO_LASTAOT"))
1088                 mono_last_aot_method = atoi (getenv ("MONO_LASTAOT"));
1089         if (getenv ("MONO_AOT_CACHE"))
1090                 use_aot_cache = TRUE;
1091 }
1092
1093 static gboolean
1094 decode_cached_class_info (MonoAotModule *module, MonoCachedClassInfo *info, guint8 *buf, guint8 **endbuf)
1095 {
1096         guint32 flags;
1097
1098         info->vtable_size = decode_value (buf, &buf);
1099         if (info->vtable_size == -1)
1100                 /* Generic type */
1101                 return FALSE;
1102         flags = decode_value (buf, &buf);
1103         info->ghcimpl = (flags >> 0) & 0x1;
1104         info->has_finalize = (flags >> 1) & 0x1;
1105         info->has_cctor = (flags >> 2) & 0x1;
1106         info->has_nested_classes = (flags >> 3) & 0x1;
1107         info->blittable = (flags >> 4) & 0x1;
1108         info->has_references = (flags >> 5) & 0x1;
1109         info->has_static_refs = (flags >> 6) & 0x1;
1110         info->no_special_static_fields = (flags >> 7) & 0x1;
1111
1112         if (info->has_cctor) {
1113                 MonoImage *cctor_image = decode_method_ref (module, &info->cctor_token, NULL, buf, &buf);
1114                 if (!cctor_image)
1115                         return FALSE;
1116         }
1117         if (info->has_finalize) {
1118                 info->finalize_image = decode_method_ref (module, &info->finalize_token, NULL, buf, &buf);
1119                 if (!info->finalize_image)
1120                         return FALSE;
1121         }
1122
1123         info->instance_size = decode_value (buf, &buf);
1124         info->class_size = decode_value (buf, &buf);
1125         info->packing_size = decode_value (buf, &buf);
1126         info->min_align = decode_value (buf, &buf);
1127
1128         *endbuf = buf;
1129
1130         return TRUE;
1131 }       
1132
1133 gpointer
1134 mono_aot_get_method_from_vt_slot (MonoDomain *domain, MonoVTable *vtable, int slot)
1135 {
1136         int i;
1137         MonoClass *klass = vtable->klass;
1138         MonoAotModule *aot_module = klass->image->aot_module;
1139         guint8 *info, *p;
1140         MonoCachedClassInfo class_info;
1141         gboolean err;
1142         guint32 token;
1143         MonoImage *image;
1144
1145         if (MONO_CLASS_IS_INTERFACE (klass) || klass->rank || !aot_module)
1146                 return NULL;
1147
1148         info = &aot_module->class_info [aot_module->class_info_offsets [mono_metadata_token_index (klass->type_token) - 1]];
1149         p = info;
1150
1151         err = decode_cached_class_info (aot_module, &class_info, p, &p);
1152         if (!err)
1153                 return NULL;
1154
1155         for (i = 0; i < slot; ++i)
1156                 decode_method_ref (aot_module, &token, NULL, p, &p);
1157
1158         image = decode_method_ref (aot_module, &token, NULL, p, &p);
1159         if (!image)
1160                 return NULL;
1161
1162         return mono_aot_get_method_from_token (domain, image, token);
1163 }
1164
1165 gboolean
1166 mono_aot_get_cached_class_info (MonoClass *klass, MonoCachedClassInfo *res)
1167 {
1168         MonoAotModule *aot_module = klass->image->aot_module;
1169         guint8 *p;
1170         gboolean err;
1171
1172         if (klass->rank || !aot_module)
1173                 return FALSE;
1174
1175         p = (guint8*)&aot_module->class_info [aot_module->class_info_offsets [mono_metadata_token_index (klass->type_token) - 1]];
1176
1177         err = decode_cached_class_info (aot_module, res, p, &p);
1178         if (!err)
1179                 return FALSE;
1180
1181         return TRUE;
1182 }
1183
1184 /**
1185  * mono_aot_get_class_from_name:
1186  *
1187  *  Obtains a MonoClass with a given namespace and a given name which is located in IMAGE,
1188  * using a cache stored in the AOT file.
1189  * Stores the resulting class in *KLASS if found, stores NULL otherwise.
1190  *
1191  * Returns: TRUE if the klass was found/not found in the cache, FALSE if no aot file was 
1192  * found.
1193  */
1194 gboolean
1195 mono_aot_get_class_from_name (MonoImage *image, const char *name_space, const char *name, MonoClass **klass)
1196 {
1197         MonoAotModule *aot_module = image->aot_module;
1198         guint16 *table, *entry;
1199         guint16 table_size;
1200         guint32 hash;
1201         char full_name_buf [1024];
1202         char *full_name;
1203         const char *name2, *name_space2;
1204         MonoTableInfo  *t;
1205         guint32 cols [MONO_TYPEDEF_SIZE];
1206         GHashTable *nspace_table;
1207
1208         if (!aot_module || !aot_module->class_name_table)
1209                 return FALSE;
1210
1211         mono_aot_lock ();
1212
1213         *klass = NULL;
1214
1215         /* First look in the cache */
1216         if (!aot_module->name_cache)
1217                 aot_module->name_cache = g_hash_table_new (g_str_hash, g_str_equal);
1218         nspace_table = g_hash_table_lookup (aot_module->name_cache, name_space);
1219         if (nspace_table) {
1220                 *klass = g_hash_table_lookup (nspace_table, name);
1221                 if (*klass) {
1222                         mono_aot_unlock ();
1223                         return TRUE;
1224                 }
1225         }
1226
1227         table_size = aot_module->class_name_table [0];
1228         table = aot_module->class_name_table + 1;
1229
1230         if (name_space [0] == '\0')
1231                 full_name = g_strdup_printf ("%s", name);
1232         else {
1233                 if (strlen (name_space) + strlen (name) < 1000) {
1234                         sprintf (full_name_buf, "%s.%s", name_space, name);
1235                         full_name = full_name_buf;
1236                 } else {
1237                         full_name = g_strdup_printf ("%s.%s", name_space, name);
1238                 }
1239         }
1240         hash = g_str_hash (full_name) % table_size;
1241         if (full_name != full_name_buf)
1242                 g_free (full_name);
1243
1244         entry = &table [hash * 2];
1245
1246         if (entry [0] != 0) {
1247                 t = &image->tables [MONO_TABLE_TYPEDEF];
1248
1249                 while (TRUE) {
1250                         guint32 index = entry [0];
1251                         guint32 next = entry [1];
1252                         guint32 token = mono_metadata_make_token (MONO_TABLE_TYPEDEF, index);
1253
1254                         name_table_accesses ++;
1255
1256                         mono_metadata_decode_row (t, index - 1, cols, MONO_TYPEDEF_SIZE);
1257
1258                         name2 = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
1259                         name_space2 = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
1260
1261                         if (!strcmp (name, name2) && !strcmp (name_space, name_space2)) {
1262                                 mono_aot_unlock ();
1263                                 *klass = mono_class_get (image, token);
1264
1265                                 /* Add to cache */
1266                                 if (*klass) {
1267                                         mono_aot_lock ();
1268                                         nspace_table = g_hash_table_lookup (aot_module->name_cache, name_space);
1269                                         if (!nspace_table) {
1270                                                 nspace_table = g_hash_table_new (g_str_hash, g_str_equal);
1271                                                 g_hash_table_insert (aot_module->name_cache, (char*)name_space2, nspace_table);
1272                                         }
1273                                         g_hash_table_insert (nspace_table, (char*)name2, *klass);
1274                                         mono_aot_unlock ();
1275                                 }
1276                                 return TRUE;
1277                         }
1278
1279                         if (next != 0) {
1280                                 entry = &table [next * 2];
1281                         } else {
1282                                 break;
1283                         }
1284                 }
1285         }
1286
1287         mono_aot_unlock ();
1288         
1289         return TRUE;
1290 }
1291
1292 static MonoJitInfo*
1293 decode_exception_debug_info (MonoAotModule *aot_module, MonoDomain *domain, 
1294                                                          MonoMethod *method, guint8* ex_info, guint8 *code)
1295 {
1296         int i, buf_len;
1297         MonoJitInfo *jinfo;
1298         guint code_len, used_int_regs;
1299         gboolean has_generic_jit_info;
1300         guint8 *p;
1301         MonoMethodHeader *header;
1302         int generic_info_size;
1303
1304         header = mono_method_get_header (method);
1305
1306         /* Load the method info from the AOT file */
1307
1308         p = ex_info;
1309         code_len = decode_value (p, &p);
1310         used_int_regs = decode_value (p, &p);
1311         has_generic_jit_info = decode_value (p, &p);
1312         if (has_generic_jit_info)
1313                 generic_info_size = sizeof (MonoGenericJitInfo);
1314         else
1315                 generic_info_size = 0;
1316
1317         /* Exception table */
1318         if (header && header->num_clauses) {
1319                 jinfo = 
1320                         mono_domain_alloc0 (domain, sizeof (MonoJitInfo) + (sizeof (MonoJitExceptionInfo) * header->num_clauses) + generic_info_size);
1321                 jinfo->num_clauses = header->num_clauses;
1322
1323                 for (i = 0; i < header->num_clauses; ++i) {
1324                         MonoExceptionClause *ec = &header->clauses [i];                         
1325                         MonoJitExceptionInfo *ei = &jinfo->clauses [i];
1326
1327                         ei->flags = ec->flags;
1328                         ei->exvar_offset = decode_value (p, &p);
1329
1330                         if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)
1331                                 ei->data.filter = code + decode_value (p, &p);
1332                         else
1333                                 ei->data.catch_class = ec->data.catch_class;
1334
1335                         ei->try_start = code + decode_value (p, &p);
1336                         ei->try_end = code + decode_value (p, &p);
1337                         ei->handler_start = code + decode_value (p, &p);
1338                 }
1339         }
1340         else
1341                 jinfo = mono_domain_alloc0 (domain, sizeof (MonoJitInfo) + generic_info_size);
1342
1343         jinfo->code_size = code_len;
1344         jinfo->used_regs = used_int_regs;
1345         jinfo->method = method;
1346         jinfo->code_start = code;
1347         jinfo->domain_neutral = 0;
1348
1349         if (has_generic_jit_info) {
1350                 MonoGenericJitInfo *gi;
1351
1352                 jinfo->has_generic_jit_info = 1;
1353
1354                 gi = mono_jit_info_get_generic_jit_info (jinfo);
1355                 g_assert (gi);
1356
1357                 gi->has_this = decode_value (p, &p);
1358                 gi->this_reg = decode_value (p, &p);
1359                 gi->this_offset = decode_value (p, &p);
1360
1361                 /* This currently contains no data */
1362                 gi->generic_sharing_context = g_new0 (MonoGenericSharingContext, 1);
1363
1364                 jinfo->method = decode_method_ref_2 (aot_module, p, &p);
1365         }
1366
1367         /* Load debug info */
1368         buf_len = decode_value (p, &p);
1369         mono_debug_add_aot_method (domain, method, code, p, buf_len);
1370         
1371         return jinfo;
1372 }
1373
1374 MonoJitInfo *
1375 mono_aot_find_jit_info (MonoDomain *domain, MonoImage *image, gpointer addr)
1376 {
1377         int pos, left, right, offset, offset1, offset2, last_offset, new_offset, page_index, method_index, table_len;
1378         guint32 token;
1379         MonoAotModule *aot_module = image->aot_module;
1380         MonoMethod *method;
1381         MonoJitInfo *jinfo;
1382         guint8 *code, *ex_info;
1383         guint32 *table, *ptr;
1384         gboolean found;
1385
1386         if (!aot_module)
1387                 return NULL;
1388
1389         if (domain != mono_get_root_domain ())
1390                 /* FIXME: */
1391                 return NULL;
1392
1393         offset = (guint8*)addr - aot_module->code;
1394
1395         /* First search through the index */
1396         ptr = aot_module->method_order;
1397         last_offset = 0;
1398         page_index = 0;
1399         found = FALSE;
1400
1401         if (*ptr == 0xffffff)
1402                 return NULL;
1403         ptr ++;
1404
1405         while (*ptr != 0xffffff) {
1406                 guint32 method_index = ptr [0];
1407                 new_offset = aot_module->code_offsets [method_index];
1408
1409                 if (offset >= last_offset && offset < new_offset) {
1410                         found = TRUE;
1411                         break;
1412                 }
1413
1414                 ptr ++;
1415                 last_offset = new_offset;
1416                 page_index ++;
1417         }
1418
1419         /* Skip rest of index */
1420         while (*ptr != 0xffffff)
1421                 ptr ++;
1422         ptr ++;
1423
1424         table = ptr;
1425         table_len = aot_module->method_order_end - table;
1426
1427         g_assert (table <= aot_module->method_order_end);
1428
1429         if (found) {
1430                 left = (page_index * 1024);
1431                 right = left + 1024;
1432
1433                 if (right > table_len)
1434                         right = table_len;
1435
1436                 offset1 = aot_module->code_offsets [table [left]];
1437                 g_assert (offset1 <= offset);
1438
1439                 //printf ("Found in index: 0x%x 0x%x 0x%x\n", offset, last_offset, new_offset);
1440         }
1441         else {
1442                 //printf ("Not found in index: 0x%x\n", offset);
1443                 left = 0;
1444                 right = table_len;
1445         }
1446
1447         /* Binary search inside the method_order table to find the method */
1448         while (TRUE) {
1449                 pos = (left + right) / 2;
1450
1451                 g_assert (table + pos <= aot_module->method_order_end);
1452
1453                 //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]]);
1454
1455                 offset1 = aot_module->code_offsets [table [pos]];
1456                 if (table + pos + 1 >= aot_module->method_order_end)
1457                         offset2 = aot_module->code_end - aot_module->code;
1458                 else
1459                         offset2 = aot_module->code_offsets [table [pos + 1]];
1460
1461                 if (offset < offset1)
1462                         right = pos;
1463                 else if (offset >= offset2)
1464                         left = pos + 1;
1465                 else
1466                         break;
1467         }
1468
1469         method_index = table [pos];
1470
1471         /* Might be a wrapper */
1472         if (aot_module->wrappers) {
1473                 mono_aot_lock ();
1474                 method = g_hash_table_lookup (aot_module->wrappers, GUINT_TO_POINTER (method_index));
1475                 mono_aot_unlock ();
1476         } else {
1477                 method = NULL;
1478         }
1479
1480         if (!method) {
1481                 token = mono_metadata_make_token (MONO_TABLE_METHOD, method_index + 1);
1482                 method = mono_get_method (image, token, NULL);
1483         }
1484
1485         /* FIXME: */
1486         g_assert (method);
1487
1488         //printf ("F: %s\n", mono_method_full_name (method, TRUE));
1489
1490         code = &aot_module->code [aot_module->code_offsets [method_index]];
1491         ex_info = &aot_module->ex_info [aot_module->ex_info_offsets [method_index]];
1492
1493         jinfo = decode_exception_debug_info (aot_module, domain, method, ex_info, code);
1494
1495         g_assert ((guint8*)addr >= (guint8*)jinfo->code_start);
1496         g_assert ((guint8*)addr < (guint8*)jinfo->code_start + jinfo->code_size);
1497
1498         /* Add it to the normal JitInfo tables */
1499         mono_jit_info_table_add (domain, jinfo);
1500         
1501         return jinfo;
1502 }
1503
1504 /* Keep it in sync with the version in aot-compiler.c */
1505 static inline gboolean
1506 is_shared_got_patch (MonoJumpInfo *patch_info)
1507 {
1508         switch (patch_info->type) {
1509         case MONO_PATCH_INFO_VTABLE:
1510         case MONO_PATCH_INFO_CLASS:
1511         case MONO_PATCH_INFO_IID:
1512         case MONO_PATCH_INFO_ADJUSTED_IID:
1513         case MONO_PATCH_INFO_FIELD:
1514         case MONO_PATCH_INFO_SFLDA:
1515         case MONO_PATCH_INFO_DECLSEC:
1516         case MONO_PATCH_INFO_LDTOKEN:
1517         case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1518         case MONO_PATCH_INFO_RVA:
1519         case MONO_PATCH_INFO_METHODCONST:
1520                 return TRUE;
1521         default:
1522                 return FALSE;
1523         }
1524 }
1525
1526 static gboolean
1527 decode_patch (MonoAotModule *aot_module, MonoMemPool *mp, MonoJumpInfo *ji, guint8 *buf, guint8 **endbuf)
1528 {
1529         guint8 *p = buf;
1530         gpointer *table;
1531         MonoImage *image;
1532         int i;
1533
1534         switch (ji->type) {
1535         case MONO_PATCH_INFO_METHOD:
1536         case MONO_PATCH_INFO_METHOD_JUMP:
1537         case MONO_PATCH_INFO_ICALL_ADDR:
1538         case MONO_PATCH_INFO_METHOD_RGCTX: {
1539                 guint32 token;
1540                 MonoMethod *method;
1541
1542                 image = decode_method_ref (aot_module, &token, &method, p, &p);
1543                 if (!image)
1544                         goto cleanup;
1545
1546 #ifdef MONO_ARCH_HAVE_CREATE_TRAMPOLINE_FROM_TOKEN
1547                 if (!method && !mono_aot_only && (ji->type == MONO_PATCH_INFO_METHOD) && (mono_metadata_token_table (token) == MONO_TABLE_METHOD)) {
1548                         ji->data.target = mono_create_jit_trampoline_from_token (image, token);
1549                         ji->type = MONO_PATCH_INFO_ABS;
1550                 }
1551                 else {
1552                         if (method)
1553                                 ji->data.method = method;
1554                         else
1555                                 ji->data.method = mono_get_method (image, token, NULL);
1556                         g_assert (ji->data.method);
1557                         mono_class_init (ji->data.method->klass);
1558                 }
1559 #else
1560                 ji->data.method = mono_get_method (image, token, NULL);
1561                 g_assert (ji->data.method);
1562                 mono_class_init (ji->data.method->klass);
1563 #endif
1564
1565                 break;
1566         }
1567         case MONO_PATCH_INFO_INTERNAL_METHOD:
1568         case MONO_PATCH_INFO_JIT_ICALL_ADDR: {
1569                 guint32 len = decode_value (p, &p);
1570
1571                 ji->data.name = (char*)p;
1572                 p += len + 1;
1573                 break;
1574         }
1575         case MONO_PATCH_INFO_METHODCONST:
1576                 /* Shared */
1577                 ji->data.method = decode_method_ref_2 (aot_module, p, &p);
1578                 if (!ji->data.method)
1579                         goto cleanup;
1580                 break;
1581         case MONO_PATCH_INFO_VTABLE:
1582         case MONO_PATCH_INFO_CLASS:
1583         case MONO_PATCH_INFO_IID:
1584         case MONO_PATCH_INFO_ADJUSTED_IID:
1585                 /* Shared */
1586                 ji->data.klass = decode_klass_ref (aot_module, p, &p);
1587                 if (!ji->data.klass)
1588                         goto cleanup;
1589                 break;
1590         case MONO_PATCH_INFO_CLASS_INIT:
1591         case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1592                 ji->data.klass = decode_klass_ref (aot_module, p, &p);
1593                 if (!ji->data.klass)
1594                         goto cleanup;
1595                 break;
1596         case MONO_PATCH_INFO_IMAGE:
1597                 ji->data.image = load_image (aot_module, decode_value (p, &p));
1598                 if (!ji->data.image)
1599                         goto cleanup;
1600                 break;
1601         case MONO_PATCH_INFO_FIELD:
1602         case MONO_PATCH_INFO_SFLDA:
1603                 /* Shared */
1604                 ji->data.field = decode_field_info (aot_module, p, &p);
1605                 if (!ji->data.field)
1606                         goto cleanup;
1607                 break;
1608         case MONO_PATCH_INFO_SWITCH:
1609                 ji->data.table = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoBBTable));
1610                 ji->data.table->table_size = decode_value (p, &p);
1611                 table = g_new (gpointer, ji->data.table->table_size);
1612                 ji->data.table->table = (MonoBasicBlock**)table;
1613                 for (i = 0; i < ji->data.table->table_size; i++)
1614                         table [i] = (gpointer)(gssize)decode_value (p, &p);
1615                 break;
1616         case MONO_PATCH_INFO_R4: {
1617                 guint32 val;
1618                 
1619                 ji->data.target = mono_mempool_alloc0 (mp, sizeof (float));
1620                 val = decode_value (p, &p);
1621                 *(float*)ji->data.target = *(float*)&val;
1622                 break;
1623         }
1624         case MONO_PATCH_INFO_R8: {
1625                 guint32 val [2];
1626
1627                 ji->data.target = mono_mempool_alloc0 (mp, sizeof (double));
1628
1629                 val [0] = decode_value (p, &p);
1630                 val [1] = decode_value (p, &p);
1631                 *(double*)ji->data.target = *(double*)val;
1632                 break;
1633         }
1634         case MONO_PATCH_INFO_LDSTR:
1635                 image = load_image (aot_module, decode_value (p, &p));
1636                 if (!image)
1637                         goto cleanup;
1638                 ji->data.token = mono_jump_info_token_new (mp, image, MONO_TOKEN_STRING + decode_value (p, &p));
1639                 break;
1640         case MONO_PATCH_INFO_RVA:
1641         case MONO_PATCH_INFO_DECLSEC:
1642         case MONO_PATCH_INFO_LDTOKEN:
1643         case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1644                 /* Shared */
1645                 image = load_image (aot_module, decode_value (p, &p));
1646                 if (!image)
1647                         goto cleanup;
1648                 ji->data.token = mono_jump_info_token_new (mp, image, decode_value (p, &p));
1649                 break;
1650         case MONO_PATCH_INFO_EXC_NAME:
1651                 ji->data.klass = decode_klass_ref (aot_module, p, &p);
1652                 if (!ji->data.klass)
1653                         goto cleanup;
1654                 ji->data.name = ji->data.klass->name;
1655                 break;
1656         case MONO_PATCH_INFO_METHOD_REL:
1657                 ji->data.offset = decode_value (p, &p);
1658                 break;
1659         case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG:
1660         case MONO_PATCH_INFO_GENERIC_CLASS_INIT:
1661                 break;
1662         case MONO_PATCH_INFO_RGCTX_FETCH: {
1663                 gboolean res;
1664                 MonoJumpInfoRgctxEntry *entry;
1665
1666                 entry = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoRgctxEntry));
1667                 entry->method = decode_method_ref_2 (aot_module, p, &p);
1668                 entry->in_mrgctx = decode_value (p, &p);
1669                 entry->info_type = decode_value (p, &p);
1670                 entry->data = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
1671                 entry->data->type = decode_value (p, &p);
1672                 
1673                 res = decode_patch (aot_module, mp, entry->data, p, &p);
1674                 if (!res)
1675                         goto cleanup;
1676                 ji->data.rgctx_entry = entry;
1677                 break;
1678         }
1679         default:
1680                 g_warning ("unhandled type %d", ji->type);
1681                 g_assert_not_reached ();
1682         }
1683
1684         *endbuf = p;
1685
1686         return TRUE;
1687
1688  cleanup:
1689         return FALSE;
1690 }
1691
1692 static gboolean
1693 decode_got_entry (MonoAotModule *aot_module, MonoMemPool *mp, MonoJumpInfo *ji, guint8 *buf, guint8 **endbuf, guint32 *got_offset)
1694 {
1695         guint8 *p = buf;
1696         guint8 *shared_p;
1697         gboolean res;
1698
1699         if (is_shared_got_patch (ji)) {
1700                 *got_offset = decode_value (p, &p);
1701
1702                 if (aot_module->got [*got_offset]) {
1703                         /* Already loaded */
1704                         //printf ("HIT!\n");
1705                 } else {
1706                         shared_p = aot_module->got_info + aot_module->got_info_offsets [*got_offset];
1707
1708                         res = decode_patch (aot_module, mp, ji, shared_p, &shared_p);
1709                         if (!res)
1710                                 return FALSE;
1711                 }
1712         } else {
1713                 res = decode_patch (aot_module, mp, ji, p, &p);
1714                 if (!res)
1715                         return FALSE;
1716         }
1717
1718         *endbuf = p;
1719         return TRUE;
1720 }
1721
1722 static MonoJumpInfo*
1723 load_patch_info (MonoAotModule *aot_module, MonoMemPool *mp, int n_patches, 
1724                                  guint32 got_index, guint32 **got_slots, 
1725                                  guint8 *buf, guint8 **endbuf)
1726 {
1727         MonoJumpInfo *patches;
1728         MonoJumpInfo *patch_info = NULL;
1729         int pindex;
1730         guint32 last_offset;
1731         guint8 *p;
1732
1733         p = buf;
1734
1735         /* First load the type + offset table */
1736         last_offset = 0;
1737         patches = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo) * n_patches);
1738
1739         for (pindex = 0; pindex < n_patches; ++pindex) {                
1740                 MonoJumpInfo *ji = &patches [pindex];
1741
1742                 ji->type = *p;
1743                 p ++;
1744
1745                 //printf ("T: %d O: %d.\n", ji->type, ji->ip.i);
1746                 ji->next = patch_info;
1747                 patch_info = ji;
1748         }
1749
1750         *got_slots = g_malloc (sizeof (guint32) * n_patches);
1751         memset (*got_slots, 0xff, sizeof (guint32) * n_patches);
1752
1753         /* Then load the other data */
1754         for (pindex = 0; pindex < n_patches; ++pindex) {
1755                 MonoJumpInfo *ji = &patches [pindex];
1756
1757                 if (!decode_got_entry (aot_module, mp, ji, p, &p, (*got_slots) + pindex))
1758                         goto cleanup;
1759
1760                 if ((*got_slots) [pindex] == 0xffffffff)
1761                         (*got_slots) [pindex] = got_index ++;
1762         }
1763
1764         *endbuf = p;
1765         return patches;
1766
1767  cleanup:
1768         g_free (*got_slots);
1769         *got_slots = NULL;
1770
1771         return NULL;
1772 }
1773
1774 static void
1775 register_jump_target_got_slot (MonoDomain *domain, MonoMethod *method, gpointer *got_slot)
1776 {
1777         /*
1778          * Jump addresses cannot be patched by the trampoline code since it
1779          * does not have access to the caller's address. Instead, we collect
1780          * the addresses of the GOT slots pointing to a method, and patch
1781          * them after the method has been compiled.
1782          */
1783         MonoJitDomainInfo *info = domain_jit_info (domain);
1784         GSList *list;
1785                 
1786         mono_domain_lock (domain);
1787         if (!info->jump_target_got_slot_hash)
1788                 info->jump_target_got_slot_hash = g_hash_table_new (NULL, NULL);
1789         list = g_hash_table_lookup (info->jump_target_got_slot_hash, method);
1790         list = g_slist_prepend (list, got_slot);
1791         g_hash_table_insert (info->jump_target_got_slot_hash, method, list);
1792         mono_domain_unlock (domain);
1793 }
1794
1795 gpointer
1796 mono_aot_get_method (MonoDomain *domain, MonoMethod *method)
1797 {
1798         MonoClass *klass = method->klass;
1799         guint32 method_index = mono_metadata_token_index (method->token) - 1;
1800         guint8 *code, *info;
1801         MonoAotModule *aot_module = klass->image->aot_module;
1802
1803         if (!aot_module)
1804                 return NULL;
1805
1806         if (mono_profiler_get_events () & MONO_PROFILE_ENTER_LEAVE)
1807                 return NULL;
1808
1809         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
1810                 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
1811                 (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
1812                 (method->flags & METHOD_ATTRIBUTE_ABSTRACT))
1813                 return NULL;
1814
1815         g_assert (klass->inited);
1816
1817         if ((domain != mono_get_root_domain ()) && (!(aot_module->opts & MONO_OPT_SHARED)))
1818                 /* Non shared AOT code can't be used in other appdomains */
1819                 return NULL;
1820
1821         if (aot_module->out_of_date)
1822                 return NULL;
1823
1824         if (method->is_inflated) {
1825                 if (!mono_method_is_generic_sharable_impl (method, FALSE))
1826                         return NULL;
1827                 method = mono_method_get_declaring_generic_method (method);
1828         }
1829
1830         if (!method->token) {
1831                 char *full_name;
1832                 char *p;
1833
1834                 if (!method->wrapper_type || !aot_module->wrapper_info)
1835                         return NULL;
1836
1837                 mono_aot_lock ();
1838
1839                 /* Avoid doing a hash table lookup using strings if possible */
1840                 if (!aot_module->wrappers_to_code)
1841                         aot_module->wrappers_to_code = g_hash_table_new (mono_aligned_addr_hash, NULL);
1842                 code = g_hash_table_lookup (aot_module->wrappers_to_code, method);
1843                 if (code) {
1844                         mono_aot_unlock ();
1845                         return code;
1846                 }
1847
1848                 /* Try to find the wrapper among the wrapper info */
1849                 /* FIXME: This is a hack to work around the fact that runtime invoke wrappers get assigned to some random class */
1850                 if (method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE) {
1851                         char *tmpsig = mono_signature_get_desc (mono_method_signature (method), TRUE);
1852                         full_name = g_strdup_printf ("(wrapper runtime-invoke):%s (%s)", method->name, tmpsig);
1853                         g_free (tmpsig);
1854                 } else {
1855                         full_name = mono_method_full_name (method, TRUE);
1856                 }
1857
1858                 /* Create a hash table to avoid repeated linear searches */
1859                 if (!aot_module->wrappers_by_name) {
1860                         aot_module->wrappers_by_name = g_hash_table_new (g_str_hash, g_str_equal);
1861                         p = (char*)aot_module->wrapper_info;
1862                         while (*p) {
1863                                 char *end;
1864
1865                                 end = p + strlen (p) + 1;
1866                                 end = ALIGN_PTR_TO (end, 4);
1867                                 method_index = *(guint32*)end;
1868                                 end += 4;
1869                                 /* The + 1 is used to distinguish a 0 index from a not-found one */
1870                                 g_hash_table_insert (aot_module->wrappers_by_name, p, GUINT_TO_POINTER (method_index + 1));
1871                                 p = end;
1872                         }
1873                 }
1874                 method_index = GPOINTER_TO_UINT (g_hash_table_lookup (aot_module->wrappers_by_name, full_name));
1875                 mono_aot_unlock ();
1876
1877                 g_free (full_name);
1878                 if (!method_index)
1879                         return NULL;
1880
1881                 method_index --;
1882
1883                 /* Needed by find_jit_info */
1884                 mono_aot_lock ();
1885                 if (!aot_module->wrappers)
1886                         aot_module->wrappers = g_hash_table_new (NULL, NULL);
1887                 g_hash_table_insert (aot_module->wrappers, GUINT_TO_POINTER (method_index), method);
1888                 mono_aot_unlock ();
1889         }
1890
1891         if (aot_module->code_offsets [method_index] == 0xffffffff) {
1892                 if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT)) {
1893                         char *full_name = mono_method_full_name (method, TRUE);
1894                         mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT NOT FOUND: %s.\n", full_name);
1895                         g_free (full_name);
1896                 }
1897                 return NULL;
1898         }
1899
1900         code = &aot_module->code [aot_module->code_offsets [method_index]];
1901         info = &aot_module->method_info [aot_module->method_info_offsets [method_index]];
1902
1903         mono_aot_lock ();
1904         if (!aot_module->methods_loaded)
1905                 aot_module->methods_loaded = g_new0 (guint32, klass->image->tables [MONO_TABLE_METHOD].rows + 1);
1906         mono_aot_unlock ();
1907
1908         if ((aot_module->methods_loaded [method_index / 32] >> (method_index % 32)) & 0x1)
1909                 return code;
1910
1911         if (mono_last_aot_method != -1) {
1912                 if (mono_jit_stats.methods_aot > mono_last_aot_method)
1913                                 return NULL;
1914                 else
1915                         if (mono_jit_stats.methods_aot == mono_last_aot_method)
1916                                 printf ("LAST AOT METHOD: %s.%s.%s.\n", klass->name_space, klass->name, method->name);
1917         }
1918
1919         return mono_aot_load_method (domain, aot_module, method, code, info, method_index);
1920 }
1921
1922 static gpointer
1923 mono_aot_load_method (MonoDomain *domain, MonoAotModule *aot_module, MonoMethod *method, guint8 *code, guint8 *info, int method_index)
1924 {
1925         MonoClass *klass = method->klass;
1926         MonoJumpInfo *patch_info = NULL;
1927         MonoMemPool *mp;
1928         int i, pindex, got_index = 0, n_patches, used_strings;
1929         gboolean non_got_patches, keep_patches = TRUE;
1930         guint8 *p, *ex_info;
1931         MonoJitInfo *jinfo = NULL;
1932
1933         p = info;
1934         decode_klass_ref (aot_module, p, &p);
1935
1936         if (!use_loaded_code) {
1937                 guint8 *code2;
1938
1939                 if (!jinfo) {
1940                         ex_info = &aot_module->ex_info [aot_module->ex_info_offsets [mono_metadata_token_index (method->token) - 1]];
1941                         jinfo = decode_exception_debug_info (aot_module, domain, method, ex_info, code);
1942                 }
1943
1944                 mono_domain_lock (domain);
1945                 code2 = mono_code_manager_reserve (domain->code_mp, jinfo->code_size);
1946                 mono_domain_unlock (domain);
1947                 memcpy (code2, code, jinfo->code_size);
1948                 mono_arch_flush_icache (code2, jinfo->code_size);
1949                 code = code2;
1950         }
1951
1952         if (aot_module->opts & MONO_OPT_SHARED)
1953                 used_strings = decode_value (p, &p);
1954         else
1955                 used_strings = 0;
1956
1957         for (i = 0; i < used_strings; i++) {
1958                 guint token = decode_value (p, &p);
1959                 mono_ldstr (mono_get_root_domain (), klass->image, mono_metadata_token_index (token));
1960         }
1961
1962         if (aot_module->opts & MONO_OPT_SHARED) 
1963                 keep_patches = FALSE;
1964
1965         n_patches = decode_value (p, &p);
1966
1967         keep_patches = FALSE;
1968
1969         if (n_patches) {
1970                 MonoJumpInfo *patches;
1971                 guint32 *got_slots;
1972
1973                 if (keep_patches)
1974                         mp = domain->mp;
1975                 else
1976                         mp = mono_mempool_new ();
1977
1978                 got_index = decode_value (p, &p);
1979
1980                 patches = load_patch_info (aot_module, mp, n_patches, got_index, &got_slots, p, &p);
1981                 if (patches == NULL)
1982                         goto cleanup;
1983
1984                 non_got_patches = FALSE;
1985                 for (pindex = 0; pindex < n_patches; ++pindex) {
1986                         MonoJumpInfo *ji = &patches [pindex];
1987
1988                         if (is_got_patch (ji->type)) {
1989                                 if (!aot_module->got [got_slots [pindex]]) {
1990                                         aot_module->got [got_slots [pindex]] = mono_resolve_patch_target (method, domain, code, ji, TRUE);
1991                                         if (ji->type == MONO_PATCH_INFO_METHOD_JUMP)
1992                                                 register_jump_target_got_slot (domain, ji->data.method, &(aot_module->got [got_slots [pindex]]));
1993                                 }
1994                                 ji->type = MONO_PATCH_INFO_NONE;
1995                         }
1996                         else
1997                                 non_got_patches = TRUE;
1998                 }
1999                 if (non_got_patches) {
2000                         if (!jinfo) {
2001                                 ex_info = &aot_module->ex_info [aot_module->ex_info_offsets [mono_metadata_token_index (method->token) - 1]];
2002                                 jinfo = decode_exception_debug_info (aot_module, domain, method, ex_info, code);
2003                         }
2004
2005                         mono_arch_flush_icache (code, jinfo->code_size);
2006                         make_writable (code, jinfo->code_size);
2007                         mono_arch_patch_code (method, domain, code, patch_info, TRUE);
2008                 }
2009
2010                 g_free (got_slots);
2011
2012                 if (!keep_patches)
2013                         mono_mempool_destroy (mp);
2014         }
2015
2016         mono_aot_lock ();
2017
2018         mono_jit_stats.methods_aot++;
2019
2020         if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT)) {
2021                 char *full_name = mono_method_full_name (method, TRUE);
2022
2023                 if (!jinfo) {
2024                         ex_info = &aot_module->ex_info [aot_module->ex_info_offsets [method_index]];
2025                         jinfo = decode_exception_debug_info (aot_module, domain, method, ex_info, code);
2026                 }
2027
2028                 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);
2029                 g_free (full_name);
2030         }
2031
2032         aot_module->methods_loaded [method_index / 32] |= 1 << (method_index % 32);
2033
2034         init_plt (aot_module);
2035
2036         if (method->wrapper_type)
2037                 g_hash_table_insert (aot_module->wrappers_to_code, method, code);
2038
2039         mono_aot_unlock ();
2040
2041         return code;
2042
2043  cleanup:
2044         /* FIXME: The space in domain->mp is wasted */  
2045         if (aot_module->opts & MONO_OPT_SHARED)
2046                 /* No need to cache patches */
2047                 mono_mempool_destroy (mp);
2048
2049         if (jinfo)
2050                 g_free (jinfo);
2051
2052         return NULL;
2053 }
2054
2055 /**
2056  * Same as mono_aot_get_method, but we try to avoid loading any metadata from the
2057  * method.
2058  */
2059 gpointer
2060 mono_aot_get_method_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
2061 {
2062         MonoMemPool *mp;
2063         int i, method_index, pindex, got_index, n_patches, used_strings;
2064         gboolean keep_patches = TRUE;
2065         guint8 *p;
2066         guint8 *code = NULL;
2067         guint8 *info;
2068         MonoAotModule *aot_module = image->aot_module;
2069         MonoClass *klass;
2070
2071         if (!aot_module)
2072                 return NULL;
2073
2074         if (mono_profiler_get_events () & MONO_PROFILE_ENTER_LEAVE)
2075                 return NULL;
2076
2077         if (domain != mono_get_root_domain ())
2078                 return NULL;
2079
2080         if (aot_module->out_of_date)
2081                 return NULL;
2082
2083         if (aot_module->code_offsets [mono_metadata_token_index (token) - 1] == 0xffffffff) {
2084                 return NULL;
2085         }
2086
2087         method_index = mono_metadata_token_index (token) - 1;
2088         code = &aot_module->code [aot_module->code_offsets [method_index]];
2089         info = &aot_module->method_info [aot_module->method_info_offsets [method_index]];
2090
2091         mono_aot_lock ();
2092         if (!aot_module->methods_loaded)
2093                 aot_module->methods_loaded = g_new0 (guint32, image->tables [MONO_TABLE_METHOD].rows + 1);
2094         mono_aot_unlock ();
2095
2096         if ((aot_module->methods_loaded [method_index / 32] >> (method_index % 32)) & 0x1)
2097                 return code;
2098
2099         if (mono_last_aot_method != -1) {
2100                 if (mono_jit_stats.methods_aot > mono_last_aot_method)
2101                                 return NULL;
2102                 else
2103                         if (mono_jit_stats.methods_aot == mono_last_aot_method) {
2104                                 MonoMethod *method = mono_get_method (image, token, NULL);
2105                                 printf ("LAST AOT METHOD: %s.%s.%s.\n", method->klass->name_space, method->klass->name, method->name);
2106                         }
2107         }
2108
2109         p = info;
2110         klass = decode_klass_ref (aot_module, p, &p);
2111
2112         if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT)) {
2113                 MonoMethod *method = mono_get_method (image, token, NULL);
2114                 char *full_name = mono_method_full_name (method, TRUE);
2115                 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT FOUND AOT compiled code for %s %p %p\n", full_name, code, info);
2116                 g_free (full_name);
2117         }
2118
2119         if (aot_module->opts & MONO_OPT_SHARED)
2120                 used_strings = decode_value (p, &p);
2121         else
2122                 used_strings = 0;
2123
2124         for (i = 0; i < used_strings; i++) {
2125                 guint string_token = decode_value (p, &p);
2126                 mono_ldstr (mono_get_root_domain (), image, mono_metadata_token_index (string_token));
2127         }
2128
2129         if (aot_module->opts & MONO_OPT_SHARED) 
2130                 keep_patches = FALSE;
2131
2132         keep_patches = FALSE;
2133
2134         n_patches = decode_value (p, &p);
2135
2136         if (n_patches) {
2137                 MonoJumpInfo *patches;
2138                 guint32 *got_slots;
2139
2140                 if (keep_patches)
2141                         mp = domain->mp;
2142                 else
2143                         mp = mono_mempool_new ();
2144
2145                 got_index = decode_value (p, &p);
2146
2147                 patches = load_patch_info (aot_module, mp, n_patches, got_index, &got_slots, p, &p);
2148                 if (patches == NULL)
2149                         goto cleanup;
2150
2151                 for (pindex = 0; pindex < n_patches; ++pindex) {
2152                         MonoJumpInfo *ji = &patches [pindex];
2153
2154                         if (is_got_patch (ji->type)) {
2155                                 if (!aot_module->got [got_slots [pindex]]) {
2156                                         aot_module->got [got_slots [pindex]] = mono_resolve_patch_target (NULL, domain, code, ji, TRUE);
2157                                         if (ji->type == MONO_PATCH_INFO_METHOD_JUMP)
2158                                                 register_jump_target_got_slot (domain, ji->data.method, &(aot_module->got [got_slots [pindex]]));
2159                                 }
2160                                 ji->type = MONO_PATCH_INFO_NONE;
2161                         }
2162                 }
2163
2164                 g_free (got_slots);
2165
2166                 if (!keep_patches)
2167                         mono_mempool_destroy (mp);
2168         }
2169
2170         mono_jit_stats.methods_aot++;
2171
2172         mono_aot_lock ();
2173
2174         aot_module->methods_loaded [method_index / 32] |= 1 << (method_index % 32);
2175
2176         init_plt (aot_module);
2177
2178         mono_aot_unlock ();
2179
2180         if (klass)
2181                 mono_runtime_class_init (mono_class_vtable (domain, klass));
2182
2183         return code;
2184
2185  cleanup:
2186         /* FIXME: The space in domain->mp is wasted */  
2187         if (aot_module->opts & MONO_OPT_SHARED)
2188                 /* No need to cache patches */
2189                 mono_mempool_destroy (mp);
2190
2191         return NULL;
2192 }
2193
2194 typedef struct {
2195         guint8 *addr;
2196         gboolean res;
2197 } IsGotEntryUserData;
2198
2199 static void
2200 check_is_got_entry (gpointer key, gpointer value, gpointer user_data)
2201 {
2202         IsGotEntryUserData *data = (IsGotEntryUserData*)user_data;
2203         MonoAotModule *aot_module = (MonoAotModule*)value;
2204
2205         if (aot_module->got && (data->addr >= (guint8*)(aot_module->got)) && (data->addr < (guint8*)(aot_module->got + aot_module->got_size)))
2206                 data->res = TRUE;
2207 }
2208
2209 gboolean
2210 mono_aot_is_got_entry (guint8 *code, guint8 *addr)
2211 {
2212         IsGotEntryUserData user_data;
2213
2214         if (!aot_modules)
2215                 return FALSE;
2216
2217         user_data.addr = addr;
2218         user_data.res = FALSE;
2219         mono_aot_lock ();
2220         g_hash_table_foreach (aot_modules, check_is_got_entry, &user_data);
2221         mono_aot_unlock ();
2222         
2223         return user_data.res;
2224 }
2225
2226 typedef struct {
2227         guint8 *addr;
2228         MonoAotModule *module;
2229 } FindAotModuleUserData;
2230
2231 static void
2232 find_aot_module_cb (gpointer key, gpointer value, gpointer user_data)
2233 {
2234         FindAotModuleUserData *data = (FindAotModuleUserData*)user_data;
2235         MonoAotModule *aot_module = (MonoAotModule*)value;
2236
2237         if ((data->addr >= (guint8*)(aot_module->code)) && (data->addr < (guint8*)(aot_module->code_end)))
2238                 data->module = aot_module;
2239 }
2240
2241 static inline MonoAotModule*
2242 find_aot_module (guint8 *code)
2243 {
2244         FindAotModuleUserData user_data;
2245
2246         if (!aot_modules)
2247                 return NULL;
2248
2249         /* Reading these need no locking */
2250         if (((gsize)code < aot_code_low_addr) || ((gsize)code > aot_code_high_addr))
2251                 return NULL;
2252
2253         user_data.addr = code;
2254         user_data.module = NULL;
2255                 
2256         mono_aot_lock ();
2257         g_hash_table_foreach (aot_modules, find_aot_module_cb, &user_data);
2258         mono_aot_unlock ();
2259         
2260         return user_data.module;
2261 }
2262
2263 /*
2264  * mono_aot_set_make_unreadable:
2265  *
2266  *   Set whenever to make all mmaped memory unreadable. In conjuction with a
2267  * SIGSEGV handler, this is useful to find out which pages the runtime tries to read.
2268  */
2269 void
2270 mono_aot_set_make_unreadable (gboolean unreadable)
2271 {
2272         make_unreadable = unreadable;
2273 }
2274
2275 typedef struct {
2276         MonoAotModule *module;
2277         guint8 *ptr;
2278 } FindMapUserData;
2279
2280 static void
2281 find_map (gpointer key, gpointer value, gpointer user_data)
2282 {
2283         MonoAotModule *module = (MonoAotModule*)value;
2284         FindMapUserData *data = (FindMapUserData*)user_data;
2285
2286         if (!data->module)
2287                 if ((data->ptr >= module->mem_begin) && (data->ptr < module->mem_end))
2288                         data->module = module;
2289 }
2290
2291 static MonoAotModule*
2292 find_module_for_addr (void *ptr)
2293 {
2294         FindMapUserData data;
2295
2296         if (!make_unreadable)
2297                 return NULL;
2298
2299         data.module = NULL;
2300         data.ptr = (guint8*)ptr;
2301
2302         mono_aot_lock ();
2303         g_hash_table_foreach (aot_modules, (GHFunc)find_map, &data);
2304         mono_aot_unlock ();
2305
2306         return data.module;
2307 }
2308
2309 /*
2310  * mono_aot_is_pagefault:
2311  *
2312  *   Should be called from a SIGSEGV signal handler to find out whenever @ptr is
2313  * within memory allocated by this module.
2314  */
2315 gboolean
2316 mono_aot_is_pagefault (void *ptr)
2317 {
2318         if (!make_unreadable)
2319                 return FALSE;
2320
2321         return find_module_for_addr (ptr) != NULL;
2322 }
2323
2324 /*
2325  * mono_aot_handle_pagefault:
2326  *
2327  *   Handle a pagefault caused by an unreadable page by making it readable again.
2328  */
2329 void
2330 mono_aot_handle_pagefault (void *ptr)
2331 {
2332 #ifndef PLATFORM_WIN32
2333         guint8* start = (guint8*)ROUND_DOWN (((gssize)ptr), PAGESIZE);
2334         int res;
2335
2336         mono_aot_lock ();
2337         res = mprotect (start, PAGESIZE, PROT_READ|PROT_WRITE|PROT_EXEC);
2338         g_assert (res == 0);
2339
2340         n_pagefaults ++;
2341         mono_aot_unlock ();
2342
2343 #if 0
2344  {
2345         void *array [256];
2346         char **names;
2347         int i, size;
2348
2349         printf ("\nNative stacktrace:\n\n");
2350
2351         size = backtrace (array, 256);
2352         names = backtrace_symbols (array, size);
2353         for (i =0; i < size; ++i) {
2354                 printf ("\t%s\n", names [i]);
2355         }
2356         free (names);
2357  }
2358 #endif
2359
2360 #endif
2361 }
2362
2363 /*
2364  * mono_aot_plt_resolve:
2365  *
2366  *   This function is called by the entries in the PLT to resolve the actual method that
2367  * needs to be called. It returns a trampoline to the method and patches the PLT entry.
2368  */
2369 gpointer
2370 mono_aot_plt_resolve (gpointer aot_module, guint32 plt_info_offset, guint8 *code)
2371 {
2372 #ifdef MONO_ARCH_AOT_SUPPORTED
2373         guint8 *p, *target, *plt_entry;
2374         MonoJumpInfo ji;
2375         MonoAotModule *module = (MonoAotModule*)aot_module;
2376         gboolean res;
2377         MonoMemPool *mp;
2378
2379         //printf ("DYN: %p %d\n", aot_module, plt_info_offset);
2380
2381         p = &module->plt_info [plt_info_offset];
2382
2383         ji.type = decode_value (p, &p);
2384
2385         mp = mono_mempool_new_size (512);
2386         res = decode_patch (module, mp, &ji, p, &p);
2387         // FIXME: Error handling (how ?)
2388         g_assert (res);
2389
2390         target = mono_resolve_patch_target (NULL, mono_domain_get (), NULL, &ji, TRUE);
2391
2392         mono_mempool_destroy (mp);
2393
2394         /* Patch the PLT entry with target which might be the actual method not a trampoline */
2395         plt_entry = mono_aot_get_plt_entry (code);
2396         g_assert (plt_entry);
2397         mono_arch_patch_plt_entry (plt_entry, target);
2398
2399         return target;
2400 #else
2401         g_assert_not_reached ();
2402         return NULL;
2403 #endif
2404 }
2405
2406 /**
2407  * init_plt:
2408  *
2409  *   Initialize the PLT table of the AOT module. Called lazily when the first AOT
2410  * method in the module is loaded to avoid committing memory by writing to it.
2411  * LOCKING: Assumes the AOT lock is held.
2412  */
2413 static void
2414 init_plt (MonoAotModule *info)
2415 {
2416 #ifdef MONO_ARCH_AOT_SUPPORTED
2417 #ifdef __i386__
2418         guint8 *buf = info->plt;
2419 #elif defined(__x86_64__)
2420         int i, n_entries;
2421 #elif defined(__arm__)
2422         int i, n_entries;
2423 #endif
2424         gpointer tramp;
2425
2426         if (info->plt_inited)
2427                 return;
2428
2429         tramp = mono_create_specific_trampoline (info, MONO_TRAMPOLINE_AOT_PLT, mono_get_root_domain (), NULL);
2430
2431 #ifdef __i386__
2432         /* Initialize the first PLT entry */
2433         make_writable (info->plt, info->plt_end - info->plt);
2434         x86_jump_code (buf, tramp);
2435 #elif defined(__x86_64__) || defined(__arm__)
2436         /*
2437          * Initialize the entries in the plt_jump_table to point to the default targets.
2438          */
2439          n_entries = info->plt_jump_table_size / sizeof (gpointer);
2440
2441          /* The first entry points to the AOT trampoline */
2442          ((gpointer*)info->plt_jump_table)[0] = tramp;
2443          for (i = 1; i < n_entries; ++i)
2444                  /* All the default entries point to the first entry */
2445                  ((gpointer*)info->plt_jump_table)[i] = info->plt;
2446 #else
2447         g_assert_not_reached ();
2448 #endif
2449
2450         info->plt_inited = TRUE;
2451 #endif
2452 }
2453
2454 /*
2455  * mono_aot_get_plt_entry:
2456  *
2457  *   Return the address of the PLT entry called by the code at CODE if exists.
2458  */
2459 guint8*
2460 mono_aot_get_plt_entry (guint8 *code)
2461 {
2462         MonoAotModule *aot_module = find_aot_module (code);
2463 #if defined(__arm__)
2464         guint32 ins;
2465 #endif
2466
2467         if (!aot_module)
2468                 return NULL;
2469
2470 #if defined(__i386__) || defined(__x86_64__)
2471         if (code [-5] == 0xe8) {
2472                 guint32 disp = *(guint32*)(code - 4);
2473                 guint8 *target = code + disp;
2474
2475                 if ((target >= (guint8*)(aot_module->plt)) && (target < (guint8*)(aot_module->plt_end)))
2476                         return target;
2477         }
2478 #elif defined(__arm__)
2479         ins = ((guint32*)(gpointer)code) [-1];
2480
2481         /* Should be a 'bl' */
2482         if ((((ins >> 25) & 0x7) == 0x5) && (((ins >> 24) & 0x1) == 0x1)) {
2483                 gint32 disp = ((gint32)ins) & 0xffffff;
2484                 guint8 *target = code - 4 + 8 + (disp * 4);
2485
2486                 if ((target >= (guint8*)(aot_module->plt)) && (target < (guint8*)(aot_module->plt_end)))
2487                         return target;
2488         }               
2489 #else
2490         g_assert_not_reached ();
2491 #endif
2492
2493         return NULL;
2494 }
2495
2496 /*
2497  * mono_aot_get_plt_info_offset:
2498  *
2499  *   Return the PLT info offset belonging to the plt entry called by CODE.
2500  */
2501 guint32
2502 mono_aot_get_plt_info_offset (gssize *regs, guint8 *code)
2503 {
2504         guint8 *plt_entry = mono_aot_get_plt_entry (code);
2505
2506         g_assert (plt_entry);
2507
2508         /* The offset is embedded inside the code after the plt entry */
2509 #if defined(__i386__)
2510         return *(guint32*)(plt_entry + 5);
2511 #elif defined(__x86_64__)
2512         return *(guint32*)(plt_entry + 6);
2513 #elif defined(__arm__)
2514         /* The offset is stored as the 5th word of the plt entry */
2515         return ((guint32*)plt_entry) [4];
2516 #else
2517         g_assert_not_reached ();
2518         return 0;
2519 #endif
2520 }
2521
2522 static gpointer
2523 load_named_code (MonoAotModule *amodule, const char *name)
2524 {
2525         char *symbol;
2526         guint8 *p;
2527         int n_patches, got_index, pindex;
2528         MonoMemPool *mp;
2529         gpointer code;
2530
2531         /* Load the code */
2532
2533         symbol = g_strdup_printf ("%s", name);
2534         find_symbol (amodule->sofile, amodule->globals, symbol, (gpointer *)&code);
2535         g_free (symbol);
2536         if (!code)
2537                 g_error ("Symbol '%s' not found in AOT file '%s'.\n", name, amodule->aot_name);
2538
2539         mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT FOUND function '%s' in AOT file '%s'.\n", name, amodule->aot_name);
2540
2541         /* Load info */
2542
2543         symbol = g_strdup_printf ("%s_p", name);
2544         find_symbol (amodule->sofile, amodule->globals, symbol, (gpointer *)&p);
2545         g_free (symbol);
2546         if (!p)
2547                 /* Nothing to patch */
2548                 return code;
2549
2550         /* Similar to mono_aot_load_method () */
2551
2552         n_patches = decode_value (p, &p);
2553
2554         if (n_patches) {
2555                 MonoJumpInfo *patches;
2556                 guint32 *got_slots;
2557
2558                 mp = mono_mempool_new ();
2559
2560                 got_index = decode_value (p, &p);
2561
2562                 patches = load_patch_info (amodule, mp, n_patches, got_index, &got_slots, p, &p);
2563                 g_assert (patches);
2564
2565                 for (pindex = 0; pindex < n_patches; ++pindex) {
2566                         MonoJumpInfo *ji = &patches [pindex];
2567                         gpointer target;
2568
2569                         /*
2570                          * When this code is executed, the runtime may not yet initalized, so
2571                          * resolve the patch info by hand.
2572                          */
2573                         if (ji->type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
2574                                 if (!strcmp (ji->data.name, "mono_get_lmf_addr")) {
2575                                         target = mono_get_lmf_addr;
2576                                 } else if (!strcmp (ji->data.name, "mono_thread_force_interruption_checkpoint")) {
2577                                         target = mono_thread_force_interruption_checkpoint;
2578                                 } else if (!strcmp (ji->data.name, "mono_exception_from_token")) {
2579                                         target = mono_exception_from_token;
2580                                 } else if (!strcmp (ji->data.name, "mono_throw_exception")) {
2581                                         target = mono_get_throw_exception ();
2582 #ifdef __x86_64__
2583                                 } else if (!strcmp (ji->data.name, "mono_amd64_throw_exception")) {
2584                                         target = mono_amd64_throw_exception;
2585 #endif
2586 #ifdef __arm__
2587                                 } else if (!strcmp (ji->data.name, "mono_arm_throw_exception")) {
2588                                         target = mono_arm_throw_exception;
2589 #endif
2590                                 } else if (strstr (ji->data.name, "trampoline_func_") == ji->data.name) {
2591                                         int tramp_type2 = atoi (ji->data.name + strlen ("trampoline_func_"));
2592                                         target = (gpointer)mono_get_trampoline_func (tramp_type2);
2593                                 } else if (strstr (ji->data.name, "specific_trampoline_lazy_fetch_") == ji->data.name) {
2594                                         guint32 slot = atoi (ji->data.name + strlen ("specific_trampoline_lazy_fetch_"));
2595                                         target = mono_create_specific_trampoline (GUINT_TO_POINTER (slot), MONO_TRAMPOLINE_RGCTX_LAZY_FETCH, mono_get_root_domain (), NULL);
2596                                 } else {
2597                                         fprintf (stderr, "Unknown relocation '%s'\n", ji->data.name);
2598                                         g_assert_not_reached ();
2599                                         target = NULL;
2600                                 }
2601                         } else {
2602                                 /* Hopefully the code doesn't have patches which need method or 
2603                                  * domain to be set.
2604                                  */
2605                                 target = mono_resolve_patch_target (NULL, NULL, code, ji, FALSE);
2606                         }
2607
2608                         amodule->got [got_slots [pindex]] = target;
2609                 }
2610
2611                 g_free (got_slots);
2612
2613                 mono_mempool_destroy (mp);
2614         }
2615
2616         return code;
2617 }
2618
2619 /*
2620  * Return the piece of code identified by NAME from the mscorlib AOT file.
2621  */
2622 gpointer
2623 mono_aot_get_named_code (const char *name)
2624 {
2625         MonoImage *image;
2626         MonoAotModule *amodule;
2627
2628         image = mono_defaults.corlib;
2629         g_assert (image);
2630
2631         amodule = image->aot_module;
2632         g_assert (amodule);
2633
2634         return load_named_code (amodule, name);
2635 }
2636
2637 /*
2638  * Return a specific trampoline from the AOT file.
2639  */
2640 gpointer
2641 mono_aot_create_specific_trampoline (MonoImage *image, gpointer arg1, MonoTrampolineType tramp_type, MonoDomain *domain, guint32 *code_len)
2642 {
2643         MonoAotModule *amodule;
2644         int index, tramp_size;
2645         guint8 *code, *tramp;
2646         static gpointer generic_trampolines [MONO_TRAMPOLINE_NUM];
2647
2648         /* Currently, we keep all trampolines in the mscorlib AOT image */
2649         image = mono_defaults.corlib;
2650         g_assert (image);
2651
2652         mono_aot_lock ();
2653
2654         amodule = image->aot_module;
2655         g_assert (amodule);
2656
2657         if (amodule->trampoline_index == amodule->num_trampolines)
2658                 g_error ("Ran out of trampolines in '%s' (%d)\n", image->name, amodule->num_trampolines);
2659
2660         index = amodule->trampoline_index ++;
2661
2662         mono_aot_unlock ();
2663
2664         if (!generic_trampolines [tramp_type]) {
2665                 char *symbol;
2666
2667                 symbol = g_strdup_printf ("generic_trampoline_%d", tramp_type);
2668                 generic_trampolines [tramp_type] = mono_aot_get_named_code (symbol);
2669                 g_free (symbol);
2670         }
2671
2672         tramp = generic_trampolines [tramp_type];
2673         g_assert (tramp);
2674
2675         amodule->got [amodule->first_trampoline_got_offset + (index *2)] = tramp;
2676         amodule->got [amodule->first_trampoline_got_offset + (index *2) + 1] = arg1;
2677
2678 #ifdef __x86_64__
2679         tramp_size = 16;
2680 #elif defined(__arm__)
2681         tramp_size = 28;
2682 #else
2683         tramp_size = -1;
2684         g_assert_not_reached ();
2685 #endif
2686
2687         code = amodule->trampolines + (index * tramp_size);
2688         if (code_len)
2689                 *code_len = tramp_size;
2690
2691         return code;
2692 }
2693
2694 gpointer
2695 mono_aot_get_unbox_trampoline (MonoMethod *method)
2696 {
2697         guint32 method_index = mono_metadata_token_index (method->token) - 1;
2698         MonoAotModule *amodule;
2699         char *symbol;
2700         gpointer code;
2701
2702         amodule = method->klass->image->aot_module;
2703         g_assert (amodule);
2704
2705         symbol = g_strdup_printf ("unbox_trampoline_%d", method_index);
2706         code = load_named_code (amodule, symbol);
2707         g_free (symbol);
2708         return code;
2709 }
2710
2711 gpointer
2712 mono_aot_get_lazy_fetch_trampoline (guint32 slot)
2713 {
2714         char *symbol;
2715         gpointer code;
2716
2717         symbol = g_strdup_printf ("rgctx_fetch_trampoline_%u", slot);
2718         code = load_named_code (mono_defaults.corlib->aot_module, symbol);
2719         g_free (symbol);
2720         return code;
2721 }
2722
2723 /*
2724  * mono_aot_get_n_pagefaults:
2725  *
2726  *   Return the number of times handle_pagefault is called.
2727  */
2728 guint32
2729 mono_aot_get_n_pagefaults (void)
2730 {
2731         return n_pagefaults;
2732 }
2733
2734 #else
2735 /* AOT disabled */
2736
2737 void
2738 mono_aot_init (void)
2739 {
2740 }
2741
2742 gpointer
2743 mono_aot_get_method (MonoDomain *domain, MonoMethod *method)
2744 {
2745         return NULL;
2746 }
2747
2748 gboolean
2749 mono_aot_is_got_entry (guint8 *code, guint8 *addr)
2750 {
2751         return FALSE;
2752 }
2753
2754 gboolean
2755 mono_aot_get_cached_class_info (MonoClass *klass, MonoCachedClassInfo *res)
2756 {
2757         return FALSE;
2758 }
2759
2760 gboolean
2761 mono_aot_get_class_from_name (MonoImage *image, const char *name_space, const char *name, MonoClass **klass)
2762 {
2763         return FALSE;
2764 }
2765
2766 MonoJitInfo *
2767 mono_aot_find_jit_info (MonoDomain *domain, MonoImage *image, gpointer addr)
2768 {
2769         return NULL;
2770 }
2771
2772 gpointer
2773 mono_aot_get_method_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
2774 {
2775         return NULL;
2776 }
2777
2778 gboolean
2779 mono_aot_is_pagefault (void *ptr)
2780 {
2781         return FALSE;
2782 }
2783
2784 void
2785 mono_aot_set_make_unreadable (gboolean unreadable)
2786 {
2787 }
2788
2789 guint32
2790 mono_aot_get_n_pagefaults (void)
2791 {
2792         return 0;
2793 }
2794
2795 void
2796 mono_aot_handle_pagefault (void *ptr)
2797 {
2798 }
2799
2800 guint8*
2801 mono_aot_get_plt_entry (guint8 *code)
2802 {
2803         return NULL;
2804 }
2805
2806 gpointer
2807 mono_aot_plt_resolve (gpointer aot_module, guint32 plt_info_offset, guint8 *code)
2808 {
2809         return NULL;
2810 }
2811
2812 gpointer
2813 mono_aot_get_method_from_vt_slot (MonoDomain *domain, MonoVTable *vtable, int slot)
2814 {
2815         return NULL;
2816 }
2817
2818 gpointer
2819 mono_aot_create_specific_trampolines (gpointer arg1, MonoTrampolineType tramp_type, MonoDomain *domain, guint32 *code_len)
2820 {
2821         g_assert_not_reached ();
2822         return NULL;
2823 }
2824
2825 gpointer
2826 mono_aot_get_named_code (char *name)
2827 {
2828         g_assert_not_reached ();
2829         return NULL;
2830 }
2831
2832 gpointer
2833 mono_aot_get_unbox_trampoline (MonoMethod *method)
2834 {
2835         g_assert_not_reached ();
2836         return NULL;
2837 }
2838
2839 #endif