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