Merge remote-tracking branch 'public/master'
[mono.git] / mono / metadata / domain.c
1 /*
2  * domain.c: MonoDomain functions
3  *
4  * Author:
5  *      Dietmar Maurer (dietmar@ximian.com)
6  *      Patrik Torstensson
7  *
8  * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
9  * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
10  * Copyright 2011-2012 Xamarin, Inc (http://www.xamarin.com)
11  */
12
13 #include <config.h>
14 #include <glib.h>
15 #include <string.h>
16 #include <sys/stat.h>
17
18 #include <mono/metadata/gc-internal.h>
19
20 #include <mono/utils/mono-compiler.h>
21 #include <mono/utils/mono-logger-internal.h>
22 #include <mono/utils/mono-membar.h>
23 #include <mono/utils/mono-counters.h>
24 #include <mono/utils/hazard-pointer.h>
25 #include <mono/utils/mono-tls.h>
26 #include <mono/metadata/object.h>
27 #include <mono/metadata/object-internals.h>
28 #include <mono/metadata/domain-internals.h>
29 #include <mono/metadata/class-internals.h>
30 #include <mono/metadata/assembly.h>
31 #include <mono/metadata/exception.h>
32 #include <mono/metadata/metadata-internals.h>
33 #include <mono/metadata/gc-internal.h>
34 #include <mono/metadata/appdomain.h>
35 #include <mono/metadata/mono-debug-debugger.h>
36 #include <mono/metadata/mono-config.h>
37 #include <mono/metadata/threads-types.h>
38 #include <metadata/threads.h>
39 #include <metadata/profiler-private.h>
40 #include <mono/metadata/coree.h>
41
42 /* #define DEBUG_DOMAIN_UNLOAD */
43
44 /* we need to use both the Tls* functions and __thread because
45  * some archs may generate faster jit code with one meachanism
46  * or the other (we used to do it because tls slots were GC-tracked,
47  * but we can't depend on this).
48  */
49 static MonoNativeTlsKey appdomain_thread_id;
50
51 #ifdef MONO_HAVE_FAST_TLS
52
53 MONO_FAST_TLS_DECLARE(tls_appdomain);
54
55 #define GET_APPDOMAIN() ((MonoDomain*)MONO_FAST_TLS_GET(tls_appdomain))
56
57 #define SET_APPDOMAIN(x) do { \
58         MONO_FAST_TLS_SET (tls_appdomain,x); \
59         mono_native_tls_set_value (appdomain_thread_id, x); \
60         mono_gc_set_current_thread_appdomain (x); \
61 } while (FALSE)
62
63 #else /* !MONO_HAVE_FAST_TLS */
64
65 #define GET_APPDOMAIN() ((MonoDomain *)mono_native_tls_get_value (appdomain_thread_id))
66 #define SET_APPDOMAIN(x) do {                                           \
67                 mono_native_tls_set_value (appdomain_thread_id, x);     \
68                 mono_gc_set_current_thread_appdomain (x);               \
69         } while (FALSE)
70
71 #endif
72
73 #define GET_APPCONTEXT() (mono_thread_internal_current ()->current_appcontext)
74 #define SET_APPCONTEXT(x) MONO_OBJECT_SETREF (mono_thread_internal_current (), current_appcontext, (x))
75
76 static guint16 appdomain_list_size = 0;
77 static guint16 appdomain_next = 0;
78 static MonoDomain **appdomains_list = NULL;
79 static MonoImage *exe_image;
80
81 gboolean mono_dont_free_domains;
82
83 #define mono_appdomains_lock() EnterCriticalSection (&appdomains_mutex)
84 #define mono_appdomains_unlock() LeaveCriticalSection (&appdomains_mutex)
85 static CRITICAL_SECTION appdomains_mutex;
86
87 static MonoDomain *mono_root_domain = NULL;
88
89 /* some statistics */
90 static int max_domain_code_size = 0;
91 static int max_domain_code_alloc = 0;
92 static int total_domain_code_alloc = 0;
93
94 /* AppConfigInfo: Information about runtime versions supported by an 
95  * aplication.
96  */
97 typedef struct {
98         GSList *supported_runtimes;
99         char *required_runtime;
100         int configuration_count;
101         int startup_count;
102 } AppConfigInfo;
103
104 /*
105  * AotModuleInfo: Contains information about AOT modules.
106  */
107 typedef struct {
108         MonoImage *image;
109         gpointer start, end;
110 } AotModuleInfo;
111
112 static const MonoRuntimeInfo *current_runtime = NULL;
113
114 static MonoJitInfoFindInAot jit_info_find_in_aot_func = NULL;
115
116 /*
117  * Contains information about AOT loaded code.
118  */
119 static MonoAotModuleInfoTable *aot_modules = NULL;
120
121 /* This is the list of runtime versions supported by this JIT.
122  */
123 static const MonoRuntimeInfo supported_runtimes[] = {
124         {"v2.0.50215","2.0", { {2,0,0,0},    {8,0,0,0}, { 3, 5, 0, 0 } }        },
125         {"v2.0.50727","2.0", { {2,0,0,0},    {8,0,0,0}, { 3, 5, 0, 0 } }        },
126         {"v4.0.30319","4.5", { {4,0,0,0},    {10,0,0,0}, { 4, 0, 0, 0 } }   },
127         {"v4.0.30128","4.0", { {4,0,0,0},    {10,0,0,0}, { 4, 0, 0, 0 } }   },
128         {"v4.0.20506","4.0", { {4,0,0,0},    {10,0,0,0}, { 4, 0, 0, 0 } }   },
129         {"moonlight", "2.1", { {2,0,5,0},    {9,0,0,0}, { 3, 5, 0, 0 } }    },
130 };
131
132
133 /* The stable runtime version */
134 #define DEFAULT_RUNTIME_VERSION "v2.0.50727"
135
136 /* Callbacks installed by the JIT */
137 static MonoCreateDomainFunc create_domain_hook;
138 static MonoFreeDomainFunc free_domain_hook;
139
140 /* This is intentionally not in the header file, so people don't misuse it. */
141 extern void _mono_debug_init_corlib (MonoDomain *domain);
142
143 static void
144 get_runtimes_from_exe (const char *exe_file, MonoImage **exe_image, const MonoRuntimeInfo** runtimes);
145
146 static const MonoRuntimeInfo*
147 get_runtime_by_version (const char *version);
148
149 static MonoImage*
150 mono_jit_info_find_aot_module (guint8* addr);
151
152 MonoNativeTlsKey
153 mono_domain_get_tls_key (void)
154 {
155         return appdomain_thread_id;
156 }
157
158 gint32
159 mono_domain_get_tls_offset (void)
160 {
161         int offset = -1;
162         MONO_THREAD_VAR_OFFSET (tls_appdomain, offset);
163 /*      __asm ("jmp 1f; .section writetext, \"awx\"; 1: movl $tls_appdomain@ntpoff, %0; jmp 2f; .previous; 2:" 
164                 : "=r" (offset));*/
165         return offset;
166 }
167
168 #define JIT_INFO_TABLE_FILL_RATIO_NOM           3
169 #define JIT_INFO_TABLE_FILL_RATIO_DENOM         4
170 #define JIT_INFO_TABLE_FILLED_NUM_ELEMENTS      (MONO_JIT_INFO_TABLE_CHUNK_SIZE * JIT_INFO_TABLE_FILL_RATIO_NOM / JIT_INFO_TABLE_FILL_RATIO_DENOM)
171
172 #define JIT_INFO_TABLE_LOW_WATERMARK(n)         ((n) / 2)
173 #define JIT_INFO_TABLE_HIGH_WATERMARK(n)        ((n) * 5 / 6)
174
175 #define JIT_INFO_TOMBSTONE_MARKER       ((MonoMethod*)NULL)
176 #define IS_JIT_INFO_TOMBSTONE(ji)       ((ji)->method == JIT_INFO_TOMBSTONE_MARKER)
177
178 #define JIT_INFO_TABLE_HAZARD_INDEX             0
179 #define JIT_INFO_HAZARD_INDEX                   1
180
181 static int
182 jit_info_table_num_elements (MonoJitInfoTable *table)
183 {
184         int i;
185         int num_elements = 0;
186
187         for (i = 0; i < table->num_chunks; ++i) {
188                 MonoJitInfoTableChunk *chunk = table->chunks [i];
189                 int chunk_num_elements = chunk->num_elements;
190                 int j;
191
192                 for (j = 0; j < chunk_num_elements; ++j) {
193                         if (!IS_JIT_INFO_TOMBSTONE (chunk->data [j]))
194                                 ++num_elements;
195                 }
196         }
197
198         return num_elements;
199 }
200
201 static MonoJitInfoTableChunk*
202 jit_info_table_new_chunk (void)
203 {
204         MonoJitInfoTableChunk *chunk = g_new0 (MonoJitInfoTableChunk, 1);
205         chunk->refcount = 1;
206
207         return chunk;
208 }
209
210 static MonoJitInfoTable *
211 jit_info_table_new (MonoDomain *domain)
212 {
213         MonoJitInfoTable *table = g_malloc0 (MONO_SIZEOF_JIT_INFO_TABLE + sizeof (MonoJitInfoTableChunk*));
214
215         table->domain = domain;
216         table->num_chunks = 1;
217         table->chunks [0] = jit_info_table_new_chunk ();
218
219         return table;
220 }
221
222 static void
223 jit_info_table_free (MonoJitInfoTable *table)
224 {
225         int i;
226         int num_chunks = table->num_chunks;
227         MonoDomain *domain = table->domain;
228
229         mono_domain_lock (domain);
230
231         table->domain->num_jit_info_tables--;
232         if (table->domain->num_jit_info_tables <= 1) {
233                 GSList *list;
234
235                 for (list = table->domain->jit_info_free_queue; list; list = list->next)
236                         g_free (list->data);
237
238                 g_slist_free (table->domain->jit_info_free_queue);
239                 table->domain->jit_info_free_queue = NULL;
240         }
241
242         /* At this point we assume that there are no other threads
243            still accessing the table, so we don't have to worry about
244            hazardous pointers. */
245
246         for (i = 0; i < num_chunks; ++i) {
247                 MonoJitInfoTableChunk *chunk = table->chunks [i];
248                 int num_elements;
249                 int j;
250
251                 if (--chunk->refcount > 0)
252                         continue;
253
254                 num_elements = chunk->num_elements;
255                 for (j = 0; j < num_elements; ++j) {
256                         MonoJitInfo *ji = chunk->data [j];
257
258                         if (IS_JIT_INFO_TOMBSTONE (ji))
259                                 g_free (ji);
260                 }
261
262                 g_free (chunk);
263         }
264
265         mono_domain_unlock (domain);
266
267         g_free (table);
268 }
269
270 /* The jit_info_table is sorted in ascending order by the end
271  * addresses of the compiled methods.  The reason why we have to do
272  * this is that once we introduce tombstones, it becomes possible for
273  * code ranges to overlap, and if we sort by code start and insert at
274  * the back of the table, we cannot guarantee that we won't overlook
275  * an entry.
276  *
277  * There are actually two possible ways to do the sorting and
278  * inserting which work with our lock-free mechanism:
279  *
280  * 1. Sort by start address and insert at the front.  When looking for
281  * an entry, find the last one with a start address lower than the one
282  * you're looking for, then work your way to the front of the table.
283  *
284  * 2. Sort by end address and insert at the back.  When looking for an
285  * entry, find the first one with an end address higher than the one
286  * you're looking for, then work your way to the end of the table.
287  *
288  * We chose the latter out of convenience.
289  */
290 static int
291 jit_info_table_index (MonoJitInfoTable *table, gint8 *addr)
292 {
293         int left = 0, right = table->num_chunks;
294
295         g_assert (left < right);
296
297         do {
298                 int pos = (left + right) / 2;
299                 MonoJitInfoTableChunk *chunk = table->chunks [pos];
300
301                 if (addr < chunk->last_code_end)
302                         right = pos;
303                 else
304                         left = pos + 1;
305         } while (left < right);
306         g_assert (left == right);
307
308         if (left >= table->num_chunks)
309                 return table->num_chunks - 1;
310         return left;
311 }
312
313 static int
314 jit_info_table_chunk_index (MonoJitInfoTableChunk *chunk, MonoThreadHazardPointers *hp, gint8 *addr)
315 {
316         int left = 0, right = chunk->num_elements;
317
318         while (left < right) {
319                 int pos = (left + right) / 2;
320                 MonoJitInfo *ji = get_hazardous_pointer((gpointer volatile*)&chunk->data [pos], hp, JIT_INFO_HAZARD_INDEX);
321                 gint8 *code_end = (gint8*)ji->code_start + ji->code_size;
322
323                 if (addr < code_end)
324                         right = pos;
325                 else
326                         left = pos + 1;
327         }
328         g_assert (left == right);
329
330         return left;
331 }
332
333 MonoJitInfo*
334 mono_jit_info_table_find (MonoDomain *domain, char *addr)
335 {
336         MonoJitInfoTable *table;
337         MonoJitInfo *ji;
338         int chunk_pos, pos;
339         MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
340         MonoImage *image;
341
342         ++mono_stats.jit_info_table_lookup_count;
343
344         /* First we have to get the domain's jit_info_table.  This is
345            complicated by the fact that a writer might substitute a
346            new table and free the old one.  What the writer guarantees
347            us is that it looks at the hazard pointers after it has
348            changed the jit_info_table pointer.  So, if we guard the
349            table by a hazard pointer and make sure that the pointer is
350            still there after we've made it hazardous, we don't have to
351            worry about the writer freeing the table. */
352         table = get_hazardous_pointer ((gpointer volatile*)&domain->jit_info_table, hp, JIT_INFO_TABLE_HAZARD_INDEX);
353
354         chunk_pos = jit_info_table_index (table, (gint8*)addr);
355         g_assert (chunk_pos < table->num_chunks);
356
357         pos = jit_info_table_chunk_index (table->chunks [chunk_pos], hp, (gint8*)addr);
358
359         /* We now have a position that's very close to that of the
360            first element whose end address is higher than the one
361            we're looking for.  If we don't have the exact position,
362            then we have a position below that one, so we'll just
363            search upward until we find our element. */
364         do {
365                 MonoJitInfoTableChunk *chunk = table->chunks [chunk_pos];
366
367                 while (pos < chunk->num_elements) {
368                         ji = get_hazardous_pointer ((gpointer volatile*)&chunk->data [pos], hp, JIT_INFO_HAZARD_INDEX);
369
370                         ++pos;
371
372                         if (IS_JIT_INFO_TOMBSTONE (ji)) {
373                                 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
374                                 continue;
375                         }
376                         if ((gint8*)addr >= (gint8*)ji->code_start
377                                         && (gint8*)addr < (gint8*)ji->code_start + ji->code_size) {
378                                 mono_hazard_pointer_clear (hp, JIT_INFO_TABLE_HAZARD_INDEX);
379                                 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
380                                 return ji;
381                         }
382
383                         /* If we find a non-tombstone element which is already
384                            beyond what we're looking for, we have to end the
385                            search. */
386                         if ((gint8*)addr < (gint8*)ji->code_start)
387                                 goto not_found;
388                 }
389
390                 ++chunk_pos;
391                 pos = 0;
392         } while (chunk_pos < table->num_chunks);
393
394  not_found:
395         if (!hp)
396                 return NULL;
397
398         mono_hazard_pointer_clear (hp, JIT_INFO_TABLE_HAZARD_INDEX);
399         mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
400
401         ji = NULL;
402
403         /* Maybe its an AOT module */
404         image = mono_jit_info_find_aot_module ((guint8*)addr);
405         if (image)
406                 ji = jit_info_find_in_aot_func (domain, image, addr);
407         
408         return ji;
409 }
410
411 static G_GNUC_UNUSED void
412 jit_info_table_check (MonoJitInfoTable *table)
413 {
414         int i;
415
416         for (i = 0; i < table->num_chunks; ++i) {
417                 MonoJitInfoTableChunk *chunk = table->chunks [i];
418                 int j;
419
420                 g_assert (chunk->refcount > 0 /* && chunk->refcount <= 8 */);
421                 if (chunk->refcount > 10)
422                         printf("warning: chunk refcount is %d\n", chunk->refcount);
423                 g_assert (chunk->num_elements <= MONO_JIT_INFO_TABLE_CHUNK_SIZE);
424
425                 for (j = 0; j < chunk->num_elements; ++j) {
426                         MonoJitInfo *this = chunk->data [j];
427                         MonoJitInfo *next;
428
429                         g_assert ((gint8*)this->code_start + this->code_size <= chunk->last_code_end);
430
431                         if (j < chunk->num_elements - 1)
432                                 next = chunk->data [j + 1];
433                         else if (i < table->num_chunks - 1) {
434                                 int k;
435
436                                 for (k = i + 1; k < table->num_chunks; ++k)
437                                         if (table->chunks [k]->num_elements > 0)
438                                                 break;
439
440                                 if (k >= table->num_chunks)
441                                         return;
442
443                                 g_assert (table->chunks [k]->num_elements > 0);
444                                 next = table->chunks [k]->data [0];
445                         } else
446                                 return;
447
448                         g_assert ((gint8*)this->code_start + this->code_size <= (gint8*)next->code_start + next->code_size);
449                 }
450         }
451 }
452
453 static MonoJitInfoTable*
454 jit_info_table_realloc (MonoJitInfoTable *old)
455 {
456         int i;
457         int num_elements = jit_info_table_num_elements (old);
458         int required_size;
459         int num_chunks;
460         int new_chunk, new_element;
461         MonoJitInfoTable *new;
462
463         /* number of needed places for elements needed */
464         required_size = (int)((long)num_elements * JIT_INFO_TABLE_FILL_RATIO_DENOM / JIT_INFO_TABLE_FILL_RATIO_NOM);
465         num_chunks = (required_size + MONO_JIT_INFO_TABLE_CHUNK_SIZE - 1) / MONO_JIT_INFO_TABLE_CHUNK_SIZE;
466
467         new = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE + sizeof (MonoJitInfoTableChunk*) * num_chunks);
468         new->domain = old->domain;
469         new->num_chunks = num_chunks;
470
471         for (i = 0; i < num_chunks; ++i)
472                 new->chunks [i] = jit_info_table_new_chunk ();
473
474         new_chunk = 0;
475         new_element = 0;
476         for (i = 0; i < old->num_chunks; ++i) {
477                 MonoJitInfoTableChunk *chunk = old->chunks [i];
478                 int chunk_num_elements = chunk->num_elements;
479                 int j;
480
481                 for (j = 0; j < chunk_num_elements; ++j) {
482                         if (!IS_JIT_INFO_TOMBSTONE (chunk->data [j])) {
483                                 g_assert (new_chunk < num_chunks);
484                                 new->chunks [new_chunk]->data [new_element] = chunk->data [j];
485                                 if (++new_element >= JIT_INFO_TABLE_FILLED_NUM_ELEMENTS) {
486                                         new->chunks [new_chunk]->num_elements = new_element;
487                                         ++new_chunk;
488                                         new_element = 0;
489                                 }
490                         }
491                 }
492         }
493
494         if (new_chunk < num_chunks) {
495                 g_assert (new_chunk == num_chunks - 1);
496                 new->chunks [new_chunk]->num_elements = new_element;
497                 g_assert (new->chunks [new_chunk]->num_elements > 0);
498         }
499
500         for (i = 0; i < num_chunks; ++i) {
501                 MonoJitInfoTableChunk *chunk = new->chunks [i];
502                 MonoJitInfo *ji = chunk->data [chunk->num_elements - 1];
503
504                 new->chunks [i]->last_code_end = (gint8*)ji->code_start + ji->code_size;
505         }
506
507         return new;
508 }
509
510 static void
511 jit_info_table_split_chunk (MonoJitInfoTableChunk *chunk, MonoJitInfoTableChunk **new1p, MonoJitInfoTableChunk **new2p)
512 {
513         MonoJitInfoTableChunk *new1 = jit_info_table_new_chunk ();
514         MonoJitInfoTableChunk *new2 = jit_info_table_new_chunk ();
515
516         g_assert (chunk->num_elements == MONO_JIT_INFO_TABLE_CHUNK_SIZE);
517
518         new1->num_elements = MONO_JIT_INFO_TABLE_CHUNK_SIZE / 2;
519         new2->num_elements = MONO_JIT_INFO_TABLE_CHUNK_SIZE - new1->num_elements;
520
521         memcpy ((void*)new1->data, (void*)chunk->data, sizeof (MonoJitInfo*) * new1->num_elements);
522         memcpy ((void*)new2->data, (void*)(chunk->data + new1->num_elements), sizeof (MonoJitInfo*) * new2->num_elements);
523
524         new1->last_code_end = (gint8*)new1->data [new1->num_elements - 1]->code_start
525                 + new1->data [new1->num_elements - 1]->code_size;
526         new2->last_code_end = (gint8*)new2->data [new2->num_elements - 1]->code_start
527                 + new2->data [new2->num_elements - 1]->code_size;
528
529         *new1p = new1;
530         *new2p = new2;
531 }
532
533 static MonoJitInfoTable*
534 jit_info_table_copy_and_split_chunk (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
535 {
536         MonoJitInfoTable *new_table = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE
537                 + sizeof (MonoJitInfoTableChunk*) * (table->num_chunks + 1));
538         int i, j;
539
540         new_table->domain = table->domain;
541         new_table->num_chunks = table->num_chunks + 1;
542
543         j = 0;
544         for (i = 0; i < table->num_chunks; ++i) {
545                 if (table->chunks [i] == chunk) {
546                         jit_info_table_split_chunk (chunk, &new_table->chunks [j], &new_table->chunks [j + 1]);
547                         j += 2;
548                 } else {
549                         new_table->chunks [j] = table->chunks [i];
550                         ++new_table->chunks [j]->refcount;
551                         ++j;
552                 }
553         }
554
555         g_assert (j == new_table->num_chunks);
556
557         return new_table;
558 }
559
560 static MonoJitInfoTableChunk*
561 jit_info_table_purify_chunk (MonoJitInfoTableChunk *old)
562 {
563         MonoJitInfoTableChunk *new = jit_info_table_new_chunk ();
564         int i, j;
565
566         j = 0;
567         for (i = 0; i < old->num_elements; ++i) {
568                 if (!IS_JIT_INFO_TOMBSTONE (old->data [i]))
569                         new->data [j++] = old->data [i];
570         }
571
572         new->num_elements = j;
573         if (new->num_elements > 0)
574                 new->last_code_end = (gint8*)new->data [j - 1]->code_start + new->data [j - 1]->code_size;
575         else
576                 new->last_code_end = old->last_code_end;
577
578         return new;
579 }
580
581 static MonoJitInfoTable*
582 jit_info_table_copy_and_purify_chunk (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
583 {
584         MonoJitInfoTable *new_table = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE
585                 + sizeof (MonoJitInfoTableChunk*) * table->num_chunks);
586         int i, j;
587
588         new_table->domain = table->domain;
589         new_table->num_chunks = table->num_chunks;
590
591         j = 0;
592         for (i = 0; i < table->num_chunks; ++i) {
593                 if (table->chunks [i] == chunk)
594                         new_table->chunks [j++] = jit_info_table_purify_chunk (table->chunks [i]);
595                 else {
596                         new_table->chunks [j] = table->chunks [i];
597                         ++new_table->chunks [j]->refcount;
598                         ++j;
599                 }
600         }
601
602         g_assert (j == new_table->num_chunks);
603
604         return new_table;
605 }
606
607 /* As we add an element to the table the case can arise that the chunk
608  * to which we need to add is already full.  In that case we have to
609  * allocate a new table and do something about that chunk.  We have
610  * several strategies:
611  *
612  * If the number of elements in the table is below the low watermark
613  * or above the high watermark, we reallocate the whole table.
614  * Otherwise we only concern ourselves with the overflowing chunk:
615  *
616  * If there are no tombstones in the chunk then we split the chunk in
617  * two, each half full.
618  *
619  * If the chunk does contain tombstones, we just make a new copy of
620  * the chunk without the tombstones, which will have room for at least
621  * the one element we have to add.
622  */
623 static MonoJitInfoTable*
624 jit_info_table_chunk_overflow (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
625 {
626         int num_elements = jit_info_table_num_elements (table);
627         int i;
628
629         if (num_elements < JIT_INFO_TABLE_LOW_WATERMARK (table->num_chunks * MONO_JIT_INFO_TABLE_CHUNK_SIZE)
630                         || num_elements > JIT_INFO_TABLE_HIGH_WATERMARK (table->num_chunks * MONO_JIT_INFO_TABLE_CHUNK_SIZE)) {
631                 //printf ("reallocing table\n");
632                 return jit_info_table_realloc (table);
633         }
634
635         /* count the number of non-tombstone elements in the chunk */
636         num_elements = 0;
637         for (i = 0; i < chunk->num_elements; ++i) {
638                 if (!IS_JIT_INFO_TOMBSTONE (chunk->data [i]))
639                         ++num_elements;
640         }
641
642         if (num_elements == MONO_JIT_INFO_TABLE_CHUNK_SIZE) {
643                 //printf ("splitting chunk\n");
644                 return jit_info_table_copy_and_split_chunk (table, chunk);
645         }
646
647         //printf ("purifying chunk\n");
648         return jit_info_table_copy_and_purify_chunk (table, chunk);
649 }
650
651 /* We add elements to the table by first making space for them by
652  * shifting the elements at the back to the right, one at a time.
653  * This results in duplicate entries during the process, but during
654  * all the time the table is in a sorted state.  Also, when an element
655  * is replaced by another one, the element that replaces it has an end
656  * address that is equal to or lower than that of the replaced
657  * element.  That property is necessary to guarantee that when
658  * searching for an element we end up at a position not higher than
659  * the one we're looking for (i.e. we either find the element directly
660  * or we end up to the left of it).
661  */
662 void
663 mono_jit_info_table_add (MonoDomain *domain, MonoJitInfo *ji)
664 {
665         MonoJitInfoTable *table;
666         int chunk_pos, pos;
667         MonoJitInfoTableChunk *chunk;
668         int num_elements;
669         int i;
670
671         g_assert (ji->method != NULL);
672
673         mono_domain_lock (domain);
674
675         ++mono_stats.jit_info_table_insert_count;
676
677         table = domain->jit_info_table;
678
679  restart:
680         chunk_pos = jit_info_table_index (table, (gint8*)ji->code_start + ji->code_size);
681         g_assert (chunk_pos < table->num_chunks);
682         chunk = table->chunks [chunk_pos];
683
684         if (chunk->num_elements >= MONO_JIT_INFO_TABLE_CHUNK_SIZE) {
685                 MonoJitInfoTable *new_table = jit_info_table_chunk_overflow (table, chunk);
686
687                 /* Debugging code, should be removed. */
688                 //jit_info_table_check (new_table);
689
690                 domain->jit_info_table = new_table;
691                 mono_memory_barrier ();
692                 domain->num_jit_info_tables++;
693                 mono_thread_hazardous_free_or_queue (table, (MonoHazardousFreeFunc)jit_info_table_free);
694                 table = new_table;
695
696                 goto restart;
697         }
698
699         /* Debugging code, should be removed. */
700         //jit_info_table_check (table);
701
702         num_elements = chunk->num_elements;
703
704         pos = jit_info_table_chunk_index (chunk, NULL, (gint8*)ji->code_start + ji->code_size);
705
706         /* First we need to size up the chunk by one, by copying the
707            last item, or inserting the first one, if the table is
708            empty. */
709         if (num_elements > 0)
710                 chunk->data [num_elements] = chunk->data [num_elements - 1];
711         else
712                 chunk->data [0] = ji;
713         mono_memory_write_barrier ();
714         chunk->num_elements = ++num_elements;
715
716         /* Shift the elements up one by one. */
717         for (i = num_elements - 2; i >= pos; --i) {
718                 mono_memory_write_barrier ();
719                 chunk->data [i + 1] = chunk->data [i];
720         }
721
722         /* Now we have room and can insert the new item. */
723         mono_memory_write_barrier ();
724         chunk->data [pos] = ji;
725
726         /* Set the high code end address chunk entry. */
727         chunk->last_code_end = (gint8*)chunk->data [chunk->num_elements - 1]->code_start
728                 + chunk->data [chunk->num_elements - 1]->code_size;
729
730         /* Debugging code, should be removed. */
731         //jit_info_table_check (table);
732
733         mono_domain_unlock (domain);
734 }
735
736 static MonoJitInfo*
737 mono_jit_info_make_tombstone (MonoJitInfo *ji)
738 {
739         MonoJitInfo *tombstone = g_new0 (MonoJitInfo, 1);
740
741         tombstone->code_start = ji->code_start;
742         tombstone->code_size = ji->code_size;
743         tombstone->method = JIT_INFO_TOMBSTONE_MARKER;
744
745         return tombstone;
746 }
747
748 /*
749  * LOCKING: domain lock
750  */
751 static void
752 mono_jit_info_free_or_queue (MonoDomain *domain, MonoJitInfo *ji)
753 {
754         if (domain->num_jit_info_tables <= 1) {
755                 /* Can it actually happen that we only have one table
756                    but ji is still hazardous? */
757                 mono_thread_hazardous_free_or_queue (ji, g_free);
758         } else {
759                 domain->jit_info_free_queue = g_slist_prepend (domain->jit_info_free_queue, ji);
760         }
761 }
762
763 void
764 mono_jit_info_table_remove (MonoDomain *domain, MonoJitInfo *ji)
765 {
766         MonoJitInfoTable *table;
767         MonoJitInfoTableChunk *chunk;
768         gpointer start = ji->code_start;
769         int chunk_pos, pos;
770
771         mono_domain_lock (domain);
772         table = domain->jit_info_table;
773
774         ++mono_stats.jit_info_table_remove_count;
775
776         chunk_pos = jit_info_table_index (table, start);
777         g_assert (chunk_pos < table->num_chunks);
778
779         pos = jit_info_table_chunk_index (table->chunks [chunk_pos], NULL, start);
780
781         do {
782                 chunk = table->chunks [chunk_pos];
783
784                 while (pos < chunk->num_elements) {
785                         if (chunk->data [pos] == ji)
786                                 goto found;
787
788                         g_assert (IS_JIT_INFO_TOMBSTONE (chunk->data [pos]));
789                         g_assert ((guint8*)chunk->data [pos]->code_start + chunk->data [pos]->code_size
790                                 <= (guint8*)ji->code_start + ji->code_size);
791
792                         ++pos;
793                 }
794
795                 ++chunk_pos;
796                 pos = 0;
797         } while (chunk_pos < table->num_chunks);
798
799  found:
800         g_assert (chunk->data [pos] == ji);
801
802         chunk->data [pos] = mono_jit_info_make_tombstone (ji);
803
804         /* Debugging code, should be removed. */
805         //jit_info_table_check (table);
806
807         mono_jit_info_free_or_queue (domain, ji);
808
809         mono_domain_unlock (domain);
810 }
811
812 static MonoAotModuleInfoTable*
813 mono_aot_module_info_table_new (void)
814 {
815         return g_array_new (FALSE, FALSE, sizeof (gpointer));
816 }
817
818 static int
819 aot_info_table_index (MonoAotModuleInfoTable *table, char *addr)
820 {
821         int left = 0, right = table->len;
822
823         while (left < right) {
824                 int pos = (left + right) / 2;
825                 AotModuleInfo *ainfo = g_array_index (table, gpointer, pos);
826                 char *start = ainfo->start;
827                 char *end = ainfo->end;
828
829                 if (addr < start)
830                         right = pos;
831                 else if (addr >= end) 
832                         left = pos + 1;
833                 else
834                         return pos;
835         }
836
837         return left;
838 }
839
840 void
841 mono_jit_info_add_aot_module (MonoImage *image, gpointer start, gpointer end)
842 {
843         AotModuleInfo *ainfo = g_new0 (AotModuleInfo, 1);
844         int pos;
845
846         ainfo->image = image;
847         ainfo->start = start;
848         ainfo->end = end;
849
850         mono_appdomains_lock ();
851
852         if (!aot_modules)
853                 aot_modules = mono_aot_module_info_table_new ();
854
855         pos = aot_info_table_index (aot_modules, start);
856
857         g_array_insert_val (aot_modules, pos, ainfo);
858
859         mono_appdomains_unlock ();
860 }
861
862 static MonoImage*
863 mono_jit_info_find_aot_module (guint8* addr)
864 {
865         guint left = 0, right;
866
867         if (!aot_modules)
868                 return NULL;
869
870         mono_appdomains_lock ();
871
872         right = aot_modules->len;
873         while (left < right) {
874                 guint pos = (left + right) / 2;
875                 AotModuleInfo *ai = g_array_index (aot_modules, gpointer, pos);
876
877                 if (addr < (guint8*)ai->start)
878                         right = pos;
879                 else if (addr >= (guint8*)ai->end)
880                         left = pos + 1;
881                 else {
882                         mono_appdomains_unlock ();
883                         return ai->image;
884                 }
885         }
886
887         mono_appdomains_unlock ();
888
889         return NULL;
890 }
891
892 void
893 mono_install_jit_info_find_in_aot (MonoJitInfoFindInAot func)
894 {
895         jit_info_find_in_aot_func = func;
896 }
897
898 gpointer
899 mono_jit_info_get_code_start (MonoJitInfo* ji)
900 {
901         return ji->code_start;
902 }
903
904 int
905 mono_jit_info_get_code_size (MonoJitInfo* ji)
906 {
907         return ji->code_size;
908 }
909
910 MonoMethod*
911 mono_jit_info_get_method (MonoJitInfo* ji)
912 {
913         return ji->method;
914 }
915
916 static gpointer
917 jit_info_key_extract (gpointer value)
918 {
919         MonoJitInfo *info = (MonoJitInfo*)value;
920
921         return info->method;
922 }
923
924 static gpointer*
925 jit_info_next_value (gpointer value)
926 {
927         MonoJitInfo *info = (MonoJitInfo*)value;
928
929         return (gpointer*)&info->next_jit_code_hash;
930 }
931
932 void
933 mono_jit_code_hash_init (MonoInternalHashTable *jit_code_hash)
934 {
935         mono_internal_hash_table_init (jit_code_hash,
936                                        mono_aligned_addr_hash,
937                                        jit_info_key_extract,
938                                        jit_info_next_value);
939 }
940
941 MonoGenericJitInfo*
942 mono_jit_info_get_generic_jit_info (MonoJitInfo *ji)
943 {
944         if (ji->has_generic_jit_info)
945                 return (MonoGenericJitInfo*)&ji->clauses [ji->num_clauses];
946         else
947                 return NULL;
948 }
949
950 /*
951  * mono_jit_info_get_generic_sharing_context:
952  * @ji: a jit info
953  *
954  * Returns the jit info's generic sharing context, or NULL if it
955  * doesn't have one.
956  */
957 MonoGenericSharingContext*
958 mono_jit_info_get_generic_sharing_context (MonoJitInfo *ji)
959 {
960         MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
961
962         if (gi)
963                 return gi->generic_sharing_context;
964         else
965                 return NULL;
966 }
967
968 /*
969  * mono_jit_info_set_generic_sharing_context:
970  * @ji: a jit info
971  * @gsctx: a generic sharing context
972  *
973  * Sets the jit info's generic sharing context.  The jit info must
974  * have memory allocated for the context.
975  */
976 void
977 mono_jit_info_set_generic_sharing_context (MonoJitInfo *ji, MonoGenericSharingContext *gsctx)
978 {
979         MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
980
981         g_assert (gi);
982
983         gi->generic_sharing_context = gsctx;
984 }
985
986 MonoTryBlockHoleTableJitInfo*
987 mono_jit_info_get_try_block_hole_table_info (MonoJitInfo *ji)
988 {
989         if (ji->has_try_block_holes) {
990                 char *ptr = (char*)&ji->clauses [ji->num_clauses];
991                 if (ji->has_generic_jit_info)
992                         ptr += sizeof (MonoGenericJitInfo);
993                 return (MonoTryBlockHoleTableJitInfo*)ptr;
994         } else {
995                 return NULL;
996         }
997 }
998
999 MonoArchEHJitInfo*
1000 mono_jit_info_get_arch_eh_info (MonoJitInfo *ji)
1001 {
1002         if (ji->has_arch_eh_info) {
1003                 char *ptr = (char*)&ji->clauses [ji->num_clauses];
1004                 if (ji->has_generic_jit_info)
1005                         ptr += sizeof (MonoGenericJitInfo);
1006                 if (ji->has_try_block_holes)
1007                         ptr += sizeof (MonoTryBlockHoleTableJitInfo);
1008                 return (MonoArchEHJitInfo*)ptr;
1009         } else {
1010                 return NULL;
1011         }
1012 }
1013
1014 void
1015 mono_install_create_domain_hook (MonoCreateDomainFunc func)
1016 {
1017         create_domain_hook = func;
1018 }
1019
1020 void
1021 mono_install_free_domain_hook (MonoFreeDomainFunc func)
1022 {
1023         free_domain_hook = func;
1024 }
1025
1026 /**
1027  * mono_string_equal:
1028  * @s1: First string to compare
1029  * @s2: Second string to compare
1030  *
1031  * Returns FALSE if the strings differ.
1032  */
1033 gboolean
1034 mono_string_equal (MonoString *s1, MonoString *s2)
1035 {
1036         int l1 = mono_string_length (s1);
1037         int l2 = mono_string_length (s2);
1038
1039         if (s1 == s2)
1040                 return TRUE;
1041         if (l1 != l2)
1042                 return FALSE;
1043
1044         return memcmp (mono_string_chars (s1), mono_string_chars (s2), l1 * 2) == 0; 
1045 }
1046
1047 /**
1048  * mono_string_hash:
1049  * @s: the string to hash
1050  *
1051  * Returns the hash for the string.
1052  */
1053 guint
1054 mono_string_hash (MonoString *s)
1055 {
1056         const guint16 *p = mono_string_chars (s);
1057         int i, len = mono_string_length (s);
1058         guint h = 0;
1059
1060         for (i = 0; i < len; i++) {
1061                 h = (h << 5) - h + *p;
1062                 p++;
1063         }
1064
1065         return h;       
1066 }
1067
1068 static gboolean
1069 mono_ptrarray_equal (gpointer *s1, gpointer *s2)
1070 {
1071         int len = GPOINTER_TO_INT (s1 [0]);
1072         if (len != GPOINTER_TO_INT (s2 [0]))
1073                 return FALSE;
1074
1075         return memcmp (s1 + 1, s2 + 1, len * sizeof(gpointer)) == 0; 
1076 }
1077
1078 static guint
1079 mono_ptrarray_hash (gpointer *s)
1080 {
1081         int i;
1082         int len = GPOINTER_TO_INT (s [0]);
1083         guint hash = 0;
1084         
1085         for (i = 1; i < len; i++)
1086                 hash += GPOINTER_TO_UINT (s [i]);
1087
1088         return hash;    
1089 }
1090
1091 /*
1092  * Allocate an id for domain and set domain->domain_id.
1093  * LOCKING: must be called while holding appdomains_mutex.
1094  * We try to assign low numbers to the domain, so it can be used
1095  * as an index in data tables to lookup domain-specific info
1096  * with minimal memory overhead. We also try not to reuse the
1097  * same id too quickly (to help debugging).
1098  */
1099 static int
1100 domain_id_alloc (MonoDomain *domain)
1101 {
1102         int id = -1, i;
1103         if (!appdomains_list) {
1104                 appdomain_list_size = 2;
1105                 appdomains_list = mono_gc_alloc_fixed (appdomain_list_size * sizeof (void*), NULL);
1106         }
1107         for (i = appdomain_next; i < appdomain_list_size; ++i) {
1108                 if (!appdomains_list [i]) {
1109                         id = i;
1110                         break;
1111                 }
1112         }
1113         if (id == -1) {
1114                 for (i = 0; i < appdomain_next; ++i) {
1115                         if (!appdomains_list [i]) {
1116                                 id = i;
1117                                 break;
1118                         }
1119                 }
1120         }
1121         if (id == -1) {
1122                 MonoDomain **new_list;
1123                 int new_size = appdomain_list_size * 2;
1124                 if (new_size >= (1 << 16))
1125                         g_assert_not_reached ();
1126                 id = appdomain_list_size;
1127                 new_list = mono_gc_alloc_fixed (new_size * sizeof (void*), NULL);
1128                 memcpy (new_list, appdomains_list, appdomain_list_size * sizeof (void*));
1129                 mono_gc_free_fixed (appdomains_list);
1130                 appdomains_list = new_list;
1131                 appdomain_list_size = new_size;
1132         }
1133         domain->domain_id = id;
1134         appdomains_list [id] = domain;
1135         appdomain_next++;
1136         if (appdomain_next > appdomain_list_size)
1137                 appdomain_next = 0;
1138         return id;
1139 }
1140
1141 static gsize domain_gc_bitmap [sizeof(MonoDomain)/4/32 + 1];
1142 static gpointer domain_gc_desc = NULL;
1143 static guint32 domain_shadow_serial = 0L;
1144
1145 MonoDomain *
1146 mono_domain_create (void)
1147 {
1148         MonoDomain *domain;
1149         guint32 shadow_serial;
1150   
1151         mono_appdomains_lock ();
1152         shadow_serial = domain_shadow_serial++;
1153   
1154         if (!domain_gc_desc) {
1155                 unsigned int i, bit = 0;
1156                 for (i = G_STRUCT_OFFSET (MonoDomain, MONO_DOMAIN_FIRST_OBJECT); i < G_STRUCT_OFFSET (MonoDomain, MONO_DOMAIN_FIRST_GC_TRACKED); i += sizeof (gpointer)) {
1157                         bit = i / sizeof (gpointer);
1158                         domain_gc_bitmap [bit / 32] |= (gsize) 1 << (bit % 32);
1159                 }
1160                 domain_gc_desc = mono_gc_make_descr_from_bitmap ((gsize*)domain_gc_bitmap, bit + 1);
1161         }
1162         mono_appdomains_unlock ();
1163
1164 #ifdef HAVE_BOEHM_GC
1165         /*
1166          * Boehm doesn't like roots inside GC allocated objects, and alloc_fixed returns
1167          * a GC_MALLOC-ed object, contrary to the api docs. This causes random crashes when
1168          * running the corlib test suite.
1169          * To solve this, we pass a NULL descriptor, and don't register roots.
1170          */
1171         domain = mono_gc_alloc_fixed (sizeof (MonoDomain), NULL);
1172 #else
1173         domain = mono_gc_alloc_fixed (sizeof (MonoDomain), domain_gc_desc);
1174         mono_gc_register_root ((char*)&(domain->MONO_DOMAIN_FIRST_GC_TRACKED), G_STRUCT_OFFSET (MonoDomain, MONO_DOMAIN_LAST_GC_TRACKED) - G_STRUCT_OFFSET (MonoDomain, MONO_DOMAIN_FIRST_GC_TRACKED), NULL);
1175 #endif
1176         domain->shadow_serial = shadow_serial;
1177         domain->domain = NULL;
1178         domain->setup = NULL;
1179         domain->friendly_name = NULL;
1180         domain->search_path = NULL;
1181
1182         mono_profiler_appdomain_event (domain, MONO_PROFILE_START_LOAD);
1183
1184         domain->mp = mono_mempool_new ();
1185         domain->code_mp = mono_code_manager_new ();
1186         domain->env = mono_g_hash_table_new_type ((GHashFunc)mono_string_hash, (GCompareFunc)mono_string_equal, MONO_HASH_KEY_VALUE_GC);
1187         domain->domain_assemblies = NULL;
1188         domain->assembly_bindings = NULL;
1189         domain->assembly_bindings_parsed = FALSE;
1190         domain->class_vtable_array = g_ptr_array_new ();
1191         domain->proxy_vtable_hash = g_hash_table_new ((GHashFunc)mono_ptrarray_hash, (GCompareFunc)mono_ptrarray_equal);
1192         domain->static_data_array = NULL;
1193         mono_jit_code_hash_init (&domain->jit_code_hash);
1194         domain->ldstr_table = mono_g_hash_table_new_type ((GHashFunc)mono_string_hash, (GCompareFunc)mono_string_equal, MONO_HASH_KEY_VALUE_GC);
1195         domain->num_jit_info_tables = 1;
1196         domain->jit_info_table = jit_info_table_new (domain);
1197         domain->jit_info_free_queue = NULL;
1198         domain->finalizable_objects_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1199         domain->track_resurrection_handles_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1200         domain->ftnptrs_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1201
1202         InitializeCriticalSection (&domain->lock);
1203         InitializeCriticalSection (&domain->assemblies_lock);
1204         InitializeCriticalSection (&domain->jit_code_hash_lock);
1205         InitializeCriticalSection (&domain->finalizable_objects_hash_lock);
1206
1207         domain->method_rgctx_hash = NULL;
1208
1209         mono_appdomains_lock ();
1210         domain_id_alloc (domain);
1211         mono_appdomains_unlock ();
1212
1213         mono_perfcounters->loader_appdomains++;
1214         mono_perfcounters->loader_total_appdomains++;
1215
1216         mono_debug_domain_create (domain);
1217
1218         if (create_domain_hook)
1219                 create_domain_hook (domain);
1220
1221         mono_profiler_appdomain_loaded (domain, MONO_PROFILE_OK);
1222         
1223         return domain;
1224 }
1225
1226 /**
1227  * mono_init_internal:
1228  * 
1229  * Creates the initial application domain and initializes the mono_defaults
1230  * structure.
1231  * This function is guaranteed to not run any IL code.
1232  * If exe_filename is not NULL, the method will determine the required runtime
1233  * from the exe configuration file or the version PE field.
1234  * If runtime_version is not NULL, that runtime version will be used.
1235  * Either exe_filename or runtime_version must be provided.
1236  *
1237  * Returns: the initial domain.
1238  */
1239 static MonoDomain *
1240 mono_init_internal (const char *filename, const char *exe_filename, const char *runtime_version)
1241 {
1242         static MonoDomain *domain = NULL;
1243         MonoAssembly *ass = NULL;
1244         MonoImageOpenStatus status = MONO_IMAGE_OK;
1245         const MonoRuntimeInfo* runtimes [G_N_ELEMENTS (supported_runtimes) + 1];
1246         int n;
1247
1248         if (domain)
1249                 g_assert_not_reached ();
1250
1251 #ifdef HOST_WIN32
1252         /* Avoid system error message boxes. */
1253         SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
1254 #endif
1255
1256 #ifndef HOST_WIN32
1257         wapi_init ();
1258 #endif
1259
1260         mono_perfcounters_init ();
1261
1262         mono_counters_register ("Max native code in a domain", MONO_COUNTER_INT|MONO_COUNTER_JIT, &max_domain_code_size);
1263         mono_counters_register ("Max code space allocated in a domain", MONO_COUNTER_INT|MONO_COUNTER_JIT, &max_domain_code_alloc);
1264         mono_counters_register ("Total code space allocated", MONO_COUNTER_INT|MONO_COUNTER_JIT, &total_domain_code_alloc);
1265
1266         mono_gc_base_init ();
1267
1268         MONO_FAST_TLS_INIT (tls_appdomain);
1269         mono_native_tls_alloc (&appdomain_thread_id, NULL);
1270
1271         InitializeCriticalSection (&appdomains_mutex);
1272
1273         mono_metadata_init ();
1274         mono_images_init ();
1275         mono_assemblies_init ();
1276         mono_classes_init ();
1277         mono_loader_init ();
1278         mono_reflection_init ();
1279
1280         /* FIXME: When should we release this memory? */
1281         MONO_GC_REGISTER_ROOT_FIXED (appdomains_list);
1282
1283         domain = mono_domain_create ();
1284         mono_root_domain = domain;
1285
1286         SET_APPDOMAIN (domain);
1287         
1288         /* Get a list of runtimes supported by the exe */
1289         if (exe_filename != NULL) {
1290                 /*
1291                  * This function will load the exe file as a MonoImage. We need to close it, but
1292                  * that would mean it would be reloaded later. So instead, we save it to
1293                  * exe_image, and close it during shutdown.
1294                  */
1295                 get_runtimes_from_exe (exe_filename, &exe_image, runtimes);
1296 #ifdef HOST_WIN32
1297                 if (!exe_image) {
1298                         exe_image = mono_assembly_open_from_bundle (exe_filename, NULL, FALSE);
1299                         if (!exe_image)
1300                                 exe_image = mono_image_open (exe_filename, NULL);
1301                 }
1302                 mono_fixup_exe_image (exe_image);
1303 #endif
1304         } else if (runtime_version != NULL) {
1305                 runtimes [0] = get_runtime_by_version (runtime_version);
1306                 runtimes [1] = NULL;
1307         }
1308
1309         if (runtimes [0] == NULL) {
1310                 const MonoRuntimeInfo *default_runtime = get_runtime_by_version (DEFAULT_RUNTIME_VERSION);
1311                 runtimes [0] = default_runtime;
1312                 runtimes [1] = NULL;
1313                 g_print ("WARNING: The runtime version supported by this application is unavailable.\n");
1314                 g_print ("Using default runtime: %s\n", default_runtime->runtime_version); 
1315         }
1316
1317         /* The selected runtime will be the first one for which there is a mscrolib.dll */
1318         for (n = 0; runtimes [n] != NULL && ass == NULL; n++) {
1319                 current_runtime = runtimes [n];
1320                 ass = mono_assembly_load_corlib (current_runtime, &status);
1321                 if (status != MONO_IMAGE_OK && status != MONO_IMAGE_ERROR_ERRNO)
1322                         break;
1323
1324         }
1325         
1326         if ((status != MONO_IMAGE_OK) || (ass == NULL)) {
1327                 switch (status){
1328                 case MONO_IMAGE_ERROR_ERRNO: {
1329                         char *corlib_file = g_build_filename (mono_assembly_getrootdir (), "mono", current_runtime->framework_version, "mscorlib.dll", NULL);
1330                         g_print ("The assembly mscorlib.dll was not found or could not be loaded.\n");
1331                         g_print ("It should have been installed in the `%s' directory.\n", corlib_file);
1332                         g_free (corlib_file);
1333                         break;
1334                 }
1335                 case MONO_IMAGE_IMAGE_INVALID:
1336                         g_print ("The file %s/mscorlib.dll is an invalid CIL image\n",
1337                                  mono_assembly_getrootdir ());
1338                         break;
1339                 case MONO_IMAGE_MISSING_ASSEMBLYREF:
1340                         g_print ("Missing assembly reference in %s/mscorlib.dll\n",
1341                                  mono_assembly_getrootdir ());
1342                         break;
1343                 case MONO_IMAGE_OK:
1344                         /* to suppress compiler warning */
1345                         break;
1346                 }
1347                 
1348                 exit (1);
1349         }
1350         mono_defaults.corlib = mono_assembly_get_image (ass);
1351
1352         mono_defaults.object_class = mono_class_from_name (
1353                 mono_defaults.corlib, "System", "Object");
1354         g_assert (mono_defaults.object_class != 0);
1355
1356         mono_defaults.void_class = mono_class_from_name (
1357                 mono_defaults.corlib, "System", "Void");
1358         g_assert (mono_defaults.void_class != 0);
1359
1360         mono_defaults.boolean_class = mono_class_from_name (
1361                 mono_defaults.corlib, "System", "Boolean");
1362         g_assert (mono_defaults.boolean_class != 0);
1363
1364         mono_defaults.byte_class = mono_class_from_name (
1365                 mono_defaults.corlib, "System", "Byte");
1366         g_assert (mono_defaults.byte_class != 0);
1367
1368         mono_defaults.sbyte_class = mono_class_from_name (
1369                 mono_defaults.corlib, "System", "SByte");
1370         g_assert (mono_defaults.sbyte_class != 0);
1371
1372         mono_defaults.int16_class = mono_class_from_name (
1373                 mono_defaults.corlib, "System", "Int16");
1374         g_assert (mono_defaults.int16_class != 0);
1375
1376         mono_defaults.uint16_class = mono_class_from_name (
1377                 mono_defaults.corlib, "System", "UInt16");
1378         g_assert (mono_defaults.uint16_class != 0);
1379
1380         mono_defaults.int32_class = mono_class_from_name (
1381                 mono_defaults.corlib, "System", "Int32");
1382         g_assert (mono_defaults.int32_class != 0);
1383
1384         mono_defaults.uint32_class = mono_class_from_name (
1385                 mono_defaults.corlib, "System", "UInt32");
1386         g_assert (mono_defaults.uint32_class != 0);
1387
1388         mono_defaults.uint_class = mono_class_from_name (
1389                 mono_defaults.corlib, "System", "UIntPtr");
1390         g_assert (mono_defaults.uint_class != 0);
1391
1392         mono_defaults.int_class = mono_class_from_name (
1393                 mono_defaults.corlib, "System", "IntPtr");
1394         g_assert (mono_defaults.int_class != 0);
1395
1396         mono_defaults.int64_class = mono_class_from_name (
1397                 mono_defaults.corlib, "System", "Int64");
1398         g_assert (mono_defaults.int64_class != 0);
1399
1400         mono_defaults.uint64_class = mono_class_from_name (
1401                 mono_defaults.corlib, "System", "UInt64");
1402         g_assert (mono_defaults.uint64_class != 0);
1403
1404         mono_defaults.single_class = mono_class_from_name (
1405                 mono_defaults.corlib, "System", "Single");
1406         g_assert (mono_defaults.single_class != 0);
1407
1408         mono_defaults.double_class = mono_class_from_name (
1409                 mono_defaults.corlib, "System", "Double");
1410         g_assert (mono_defaults.double_class != 0);
1411
1412         mono_defaults.char_class = mono_class_from_name (
1413                 mono_defaults.corlib, "System", "Char");
1414         g_assert (mono_defaults.char_class != 0);
1415
1416         mono_defaults.string_class = mono_class_from_name (
1417                 mono_defaults.corlib, "System", "String");
1418         g_assert (mono_defaults.string_class != 0);
1419
1420         mono_defaults.enum_class = mono_class_from_name (
1421                 mono_defaults.corlib, "System", "Enum");
1422         g_assert (mono_defaults.enum_class != 0);
1423
1424         mono_defaults.array_class = mono_class_from_name (
1425                 mono_defaults.corlib, "System", "Array");
1426         g_assert (mono_defaults.array_class != 0);
1427
1428         mono_defaults.delegate_class = mono_class_from_name (
1429                 mono_defaults.corlib, "System", "Delegate");
1430         g_assert (mono_defaults.delegate_class != 0 );
1431
1432         mono_defaults.multicastdelegate_class = mono_class_from_name (
1433                 mono_defaults.corlib, "System", "MulticastDelegate");
1434         g_assert (mono_defaults.multicastdelegate_class != 0 );
1435
1436         mono_defaults.asyncresult_class = mono_class_from_name (
1437                 mono_defaults.corlib, "System.Runtime.Remoting.Messaging", 
1438                 "AsyncResult");
1439         g_assert (mono_defaults.asyncresult_class != 0 );
1440
1441         mono_defaults.manualresetevent_class = mono_class_from_name (
1442                 mono_defaults.corlib, "System.Threading", "ManualResetEvent");
1443         g_assert (mono_defaults.manualresetevent_class != 0 );
1444
1445         mono_defaults.typehandle_class = mono_class_from_name (
1446                 mono_defaults.corlib, "System", "RuntimeTypeHandle");
1447         g_assert (mono_defaults.typehandle_class != 0);
1448
1449         mono_defaults.methodhandle_class = mono_class_from_name (
1450                 mono_defaults.corlib, "System", "RuntimeMethodHandle");
1451         g_assert (mono_defaults.methodhandle_class != 0);
1452
1453         mono_defaults.fieldhandle_class = mono_class_from_name (
1454                 mono_defaults.corlib, "System", "RuntimeFieldHandle");
1455         g_assert (mono_defaults.fieldhandle_class != 0);
1456
1457         mono_defaults.systemtype_class = mono_class_from_name (
1458                 mono_defaults.corlib, "System", "Type");
1459         g_assert (mono_defaults.systemtype_class != 0);
1460
1461         mono_defaults.monotype_class = mono_class_from_name (
1462                 mono_defaults.corlib, "System", "MonoType");
1463         g_assert (mono_defaults.monotype_class != 0);
1464
1465         mono_defaults.exception_class = mono_class_from_name (
1466                 mono_defaults.corlib, "System", "Exception");
1467         g_assert (mono_defaults.exception_class != 0);
1468
1469         mono_defaults.threadabortexception_class = mono_class_from_name (
1470                 mono_defaults.corlib, "System.Threading", "ThreadAbortException");
1471         g_assert (mono_defaults.threadabortexception_class != 0);
1472
1473         mono_defaults.thread_class = mono_class_from_name (
1474                 mono_defaults.corlib, "System.Threading", "Thread");
1475         g_assert (mono_defaults.thread_class != 0);
1476
1477         mono_defaults.internal_thread_class = mono_class_from_name (
1478                 mono_defaults.corlib, "System.Threading", "InternalThread");
1479         if (!mono_defaults.internal_thread_class) {
1480                 /* This can happen with an old mscorlib */
1481                 fprintf (stderr, "Corlib too old for this runtime.\n");
1482                 fprintf (stderr, "Loaded from: %s\n",
1483                                  mono_defaults.corlib? mono_image_get_filename (mono_defaults.corlib): "unknown");
1484                 exit (1);
1485         }
1486
1487         mono_defaults.appdomain_class = mono_class_from_name (
1488                 mono_defaults.corlib, "System", "AppDomain");
1489         g_assert (mono_defaults.appdomain_class != 0);
1490
1491         mono_defaults.transparent_proxy_class = mono_class_from_name (
1492                 mono_defaults.corlib, "System.Runtime.Remoting.Proxies", "TransparentProxy");
1493         g_assert (mono_defaults.transparent_proxy_class != 0);
1494
1495         mono_defaults.real_proxy_class = mono_class_from_name (
1496                 mono_defaults.corlib, "System.Runtime.Remoting.Proxies", "RealProxy");
1497         g_assert (mono_defaults.real_proxy_class != 0);
1498
1499         mono_defaults.mono_method_message_class = mono_class_from_name (
1500                 mono_defaults.corlib, "System.Runtime.Remoting.Messaging", "MonoMethodMessage");
1501         g_assert (mono_defaults.mono_method_message_class != 0);
1502
1503         mono_defaults.field_info_class = mono_class_from_name (
1504                 mono_defaults.corlib, "System.Reflection", "FieldInfo");
1505         g_assert (mono_defaults.field_info_class != 0);
1506
1507         mono_defaults.method_info_class = mono_class_from_name (
1508                 mono_defaults.corlib, "System.Reflection", "MethodInfo");
1509         g_assert (mono_defaults.method_info_class != 0);
1510
1511         mono_defaults.stringbuilder_class = mono_class_from_name (
1512                 mono_defaults.corlib, "System.Text", "StringBuilder");
1513         g_assert (mono_defaults.stringbuilder_class != 0);
1514
1515         mono_defaults.math_class = mono_class_from_name (
1516                 mono_defaults.corlib, "System", "Math");
1517         g_assert (mono_defaults.math_class != 0);
1518
1519         mono_defaults.stack_frame_class = mono_class_from_name (
1520                 mono_defaults.corlib, "System.Diagnostics", "StackFrame");
1521         g_assert (mono_defaults.stack_frame_class != 0);
1522
1523         mono_defaults.stack_trace_class = mono_class_from_name (
1524                 mono_defaults.corlib, "System.Diagnostics", "StackTrace");
1525         g_assert (mono_defaults.stack_trace_class != 0);
1526
1527         mono_defaults.marshal_class = mono_class_from_name (
1528                 mono_defaults.corlib, "System.Runtime.InteropServices", "Marshal");
1529         g_assert (mono_defaults.marshal_class != 0);
1530
1531         mono_defaults.iserializeable_class = mono_class_from_name (
1532                 mono_defaults.corlib, "System.Runtime.Serialization", "ISerializable");
1533         g_assert (mono_defaults.iserializeable_class != 0);
1534
1535         mono_defaults.serializationinfo_class = mono_class_from_name (
1536                 mono_defaults.corlib, "System.Runtime.Serialization", "SerializationInfo");
1537         g_assert (mono_defaults.serializationinfo_class != 0);
1538
1539         mono_defaults.streamingcontext_class = mono_class_from_name (
1540                 mono_defaults.corlib, "System.Runtime.Serialization", "StreamingContext");
1541         g_assert (mono_defaults.streamingcontext_class != 0);
1542
1543         mono_defaults.typed_reference_class =  mono_class_from_name (
1544                 mono_defaults.corlib, "System", "TypedReference");
1545         g_assert (mono_defaults.typed_reference_class != 0);
1546
1547         mono_defaults.argumenthandle_class =  mono_class_from_name (
1548                 mono_defaults.corlib, "System", "RuntimeArgumentHandle");
1549         g_assert (mono_defaults.argumenthandle_class != 0);
1550
1551         mono_defaults.marshalbyrefobject_class =  mono_class_from_name (
1552                 mono_defaults.corlib, "System", "MarshalByRefObject");
1553         g_assert (mono_defaults.marshalbyrefobject_class != 0);
1554
1555         mono_defaults.monitor_class =  mono_class_from_name (
1556                 mono_defaults.corlib, "System.Threading", "Monitor");
1557         g_assert (mono_defaults.monitor_class != 0);
1558
1559         mono_defaults.iremotingtypeinfo_class = mono_class_from_name (
1560                 mono_defaults.corlib, "System.Runtime.Remoting", "IRemotingTypeInfo");
1561         g_assert (mono_defaults.iremotingtypeinfo_class != 0);
1562
1563         mono_defaults.runtimesecurityframe_class = mono_class_from_name (
1564                 mono_defaults.corlib, "System.Security", "RuntimeSecurityFrame");
1565
1566         mono_defaults.executioncontext_class = mono_class_from_name (
1567                 mono_defaults.corlib, "System.Threading", "ExecutionContext");
1568
1569         mono_defaults.internals_visible_class = mono_class_from_name (
1570                 mono_defaults.corlib, "System.Runtime.CompilerServices", "InternalsVisibleToAttribute");
1571
1572         mono_defaults.critical_finalizer_object = mono_class_from_name (
1573                 mono_defaults.corlib, "System.Runtime.ConstrainedExecution", "CriticalFinalizerObject");
1574
1575         /*
1576          * mscorlib needs a little help, only now it can load its friends list (after we have
1577          * loaded the InternalsVisibleToAttribute), load it now
1578          */
1579         mono_assembly_load_friends (ass);
1580         
1581         mono_defaults.safehandle_class = mono_class_from_name (
1582                 mono_defaults.corlib, "System.Runtime.InteropServices", "SafeHandle");
1583
1584         mono_defaults.handleref_class = mono_class_from_name (
1585                 mono_defaults.corlib, "System.Runtime.InteropServices", "HandleRef");
1586
1587         mono_defaults.attribute_class = mono_class_from_name (
1588                 mono_defaults.corlib, "System", "Attribute");
1589
1590         mono_defaults.customattribute_data_class = mono_class_from_name (
1591                 mono_defaults.corlib, "System.Reflection", "CustomAttributeData");
1592
1593         /* these are initialized lazily when COM features are used */
1594         mono_defaults.variant_class = NULL;
1595         mono_defaults.com_object_class = NULL;
1596         mono_defaults.com_interop_proxy_class = NULL;
1597         mono_defaults.iunknown_class = NULL;
1598         mono_defaults.idispatch_class = NULL;
1599
1600         /*
1601          * Note that mono_defaults.generic_*_class is only non-NULL if we're
1602          * using the 2.0 corlib.
1603          */
1604         mono_class_init (mono_defaults.array_class);
1605         mono_defaults.generic_nullable_class = mono_class_from_name (
1606                 mono_defaults.corlib, "System", "Nullable`1");
1607         mono_defaults.generic_ilist_class = mono_class_from_name (
1608                 mono_defaults.corlib, "System.Collections.Generic", "IList`1");
1609
1610         domain->friendly_name = g_path_get_basename (filename);
1611
1612         _mono_debug_init_corlib (domain);
1613
1614         return domain;
1615 }
1616
1617 /**
1618  * mono_init:
1619  * 
1620  * Creates the initial application domain and initializes the mono_defaults
1621  * structure.
1622  * This function is guaranteed to not run any IL code.
1623  * The runtime is initialized using the default runtime version.
1624  *
1625  * Returns: the initial domain.
1626  */
1627 MonoDomain *
1628 mono_init (const char *domain_name)
1629 {
1630         return mono_init_internal (domain_name, NULL, DEFAULT_RUNTIME_VERSION);
1631 }
1632
1633 /**
1634  * mono_init_from_assembly:
1635  * @domain_name: name to give to the initial domain
1636  * @filename: filename to load on startup
1637  *
1638  * Used by the runtime, users should use mono_jit_init instead.
1639  *
1640  * Creates the initial application domain and initializes the mono_defaults
1641  * structure.
1642  * This function is guaranteed to not run any IL code.
1643  * The runtime is initialized using the runtime version required by the
1644  * provided executable. The version is determined by looking at the exe 
1645  * configuration file and the version PE field)
1646  *
1647  * Returns: the initial domain.
1648  */
1649 MonoDomain *
1650 mono_init_from_assembly (const char *domain_name, const char *filename)
1651 {
1652         return mono_init_internal (domain_name, filename, NULL);
1653 }
1654
1655 /**
1656  * mono_init_version:
1657  * 
1658  * Used by the runtime, users should use mono_jit_init instead.
1659  * 
1660  * Creates the initial application domain and initializes the mono_defaults
1661  * structure.
1662  *
1663  * This function is guaranteed to not run any IL code.
1664  * The runtime is initialized using the provided rutime version.
1665  *
1666  * Returns: the initial domain.
1667  */
1668 MonoDomain *
1669 mono_init_version (const char *domain_name, const char *version)
1670 {
1671         return mono_init_internal (domain_name, NULL, version);
1672 }
1673
1674 /**
1675  * mono_init_com_types:
1676  *
1677  * Initializes all types needed for COM Interop in mono_defaults structure. 
1678  */
1679 void 
1680 mono_init_com_types (void)
1681 {
1682         static gboolean initialized = FALSE;
1683
1684         if (initialized)
1685                 return;
1686         
1687         /* FIXME: do I need some threading protection here */
1688
1689         g_assert (mono_defaults.corlib);
1690
1691         mono_defaults.variant_class = mono_class_from_name (
1692                 mono_defaults.corlib, "System", "Variant");
1693         g_assert (mono_defaults.variant_class != 0);
1694
1695         mono_defaults.com_object_class = mono_class_from_name (
1696                 mono_defaults.corlib, "System", "__ComObject");
1697         g_assert (mono_defaults.com_object_class != 0);
1698
1699         mono_defaults.com_interop_proxy_class = mono_class_from_name (
1700                 mono_defaults.corlib, "Mono.Interop", "ComInteropProxy");
1701         g_assert (mono_defaults.com_interop_proxy_class != 0);
1702
1703         mono_defaults.iunknown_class = mono_class_from_name (
1704                 mono_defaults.corlib, "Mono.Interop", "IUnknown");
1705         g_assert (mono_defaults.iunknown_class != 0);
1706
1707         mono_defaults.idispatch_class = mono_class_from_name (
1708                 mono_defaults.corlib, "Mono.Interop", "IDispatch");
1709         g_assert (mono_defaults.idispatch_class != 0);
1710
1711         initialized = TRUE;
1712 }
1713
1714 /**
1715  * mono_cleanup:
1716  *
1717  * Cleans up all metadata modules. 
1718  */
1719 void
1720 mono_cleanup (void)
1721 {
1722         mono_close_exe_image ();
1723
1724         mono_defaults.corlib = NULL;
1725
1726         mono_config_cleanup ();
1727         mono_loader_cleanup ();
1728         mono_classes_cleanup ();
1729         mono_assemblies_cleanup ();
1730         mono_images_cleanup ();
1731         mono_debug_cleanup ();
1732         mono_metadata_cleanup ();
1733
1734         mono_native_tls_free (appdomain_thread_id);
1735         DeleteCriticalSection (&appdomains_mutex);
1736
1737 #ifndef HOST_WIN32
1738         wapi_cleanup ();
1739 #endif
1740 }
1741
1742 void
1743 mono_close_exe_image (void)
1744 {
1745         if (exe_image)
1746                 mono_image_close (exe_image);
1747 }
1748
1749 /**
1750  * mono_get_root_domain:
1751  *
1752  * The root AppDomain is the initial domain created by the runtime when it is
1753  * initialized.  Programs execute on this AppDomain, but can create new ones
1754  * later.   Currently there is no unmanaged API to create new AppDomains, this
1755  * must be done from managed code.
1756  *
1757  * Returns: the root appdomain, to obtain the current domain, use mono_domain_get ()
1758  */
1759 MonoDomain*
1760 mono_get_root_domain (void)
1761 {
1762         return mono_root_domain;
1763 }
1764
1765 /**
1766  * mono_domain_get:
1767  *
1768  * Returns: the current domain, to obtain the root domain use
1769  * mono_get_root_domain().
1770  */
1771 MonoDomain *
1772 mono_domain_get ()
1773 {
1774         return GET_APPDOMAIN ();
1775 }
1776
1777 void
1778 mono_domain_unset (void)
1779 {
1780         SET_APPDOMAIN (NULL);
1781 }
1782
1783 void
1784 mono_domain_set_internal_with_options (MonoDomain *domain, gboolean migrate_exception)
1785 {
1786         MonoInternalThread *thread;
1787
1788         if (mono_domain_get () == domain)
1789                 return;
1790
1791         SET_APPDOMAIN (domain);
1792         SET_APPCONTEXT (domain->default_context);
1793
1794         if (migrate_exception) {
1795                 thread = mono_thread_internal_current ();
1796                 if (!thread->abort_exc)
1797                         return;
1798
1799                 g_assert (thread->abort_exc->object.vtable->domain != domain);
1800                 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
1801                 g_assert (thread->abort_exc->object.vtable->domain == domain);
1802         }
1803 }
1804
1805 /**
1806  * mono_domain_set_internal:
1807  * @domain: the new domain
1808  *
1809  * Sets the current domain to @domain.
1810  */
1811 void
1812 mono_domain_set_internal (MonoDomain *domain)
1813 {
1814         mono_domain_set_internal_with_options (domain, TRUE);
1815 }
1816
1817 void
1818 mono_domain_foreach (MonoDomainFunc func, gpointer user_data)
1819 {
1820         int i, size;
1821         MonoDomain **copy;
1822
1823         /*
1824          * Create a copy of the data to avoid calling the user callback
1825          * inside the lock because that could lead to deadlocks.
1826          * We can do this because this function is not perf. critical.
1827          */
1828         mono_appdomains_lock ();
1829         size = appdomain_list_size;
1830         copy = mono_gc_alloc_fixed (appdomain_list_size * sizeof (void*), NULL);
1831         memcpy (copy, appdomains_list, appdomain_list_size * sizeof (void*));
1832         mono_appdomains_unlock ();
1833
1834         for (i = 0; i < size; ++i) {
1835                 if (copy [i])
1836                         func (copy [i], user_data);
1837         }
1838
1839         mono_gc_free_fixed (copy);
1840 }
1841
1842 /**
1843  * mono_domain_assembly_open:
1844  * @domain: the application domain
1845  * @name: file name of the assembly
1846  *
1847  * fixme: maybe we should integrate this with mono_assembly_open ??
1848  */
1849 MonoAssembly *
1850 mono_domain_assembly_open (MonoDomain *domain, const char *name)
1851 {
1852         MonoDomain *current;
1853         MonoAssembly *ass;
1854         GSList *tmp;
1855
1856         mono_domain_assemblies_lock (domain);
1857         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1858                 ass = tmp->data;
1859                 if (strcmp (name, ass->aname.name) == 0) {
1860                         mono_domain_assemblies_unlock (domain);
1861                         return ass;
1862                 }
1863         }
1864         mono_domain_assemblies_unlock (domain);
1865
1866         if (domain != mono_domain_get ()) {
1867                 current = mono_domain_get ();
1868
1869                 mono_domain_set (domain, FALSE);
1870                 ass = mono_assembly_open (name, NULL);
1871                 mono_domain_set (current, FALSE);
1872         } else {
1873                 ass = mono_assembly_open (name, NULL);
1874         }
1875
1876         return ass;
1877 }
1878
1879 static void
1880 free_slist (gpointer key, gpointer value, gpointer user_data)
1881 {
1882         g_slist_free (value);
1883 }
1884
1885 static void
1886 unregister_vtable_reflection_type (MonoVTable *vtable)
1887 {
1888         MonoObject *type = vtable->type;
1889
1890         if (type->vtable->klass != mono_defaults.monotype_class)
1891                 MONO_GC_UNREGISTER_ROOT_IF_MOVING (vtable->type);
1892 }
1893
1894 void
1895 mono_domain_free (MonoDomain *domain, gboolean force)
1896 {
1897         int code_size, code_alloc;
1898         GSList *tmp;
1899         if ((domain == mono_root_domain) && !force) {
1900                 g_warning ("cant unload root domain");
1901                 return;
1902         }
1903
1904         if (mono_dont_free_domains)
1905                 return;
1906
1907         mono_profiler_appdomain_event (domain, MONO_PROFILE_START_UNLOAD);
1908
1909         mono_debug_domain_unload (domain);
1910
1911         mono_appdomains_lock ();
1912         appdomains_list [domain->domain_id] = NULL;
1913         mono_appdomains_unlock ();
1914
1915         /* must do this early as it accesses fields and types */
1916         if (domain->special_static_fields) {
1917                 mono_alloc_special_static_data_free (domain->special_static_fields);
1918                 g_hash_table_destroy (domain->special_static_fields);
1919                 domain->special_static_fields = NULL;
1920         }
1921
1922         /*
1923          * We must destroy all these hash tables here because they
1924          * contain references to managed objects belonging to the
1925          * domain.  Once we let the GC clear the domain there must be
1926          * no more such references, or we'll crash if a collection
1927          * occurs.
1928          */
1929         mono_g_hash_table_destroy (domain->ldstr_table);
1930         domain->ldstr_table = NULL;
1931
1932         mono_g_hash_table_destroy (domain->env);
1933         domain->env = NULL;
1934
1935         if (domain->tlsrec_list) {
1936                 mono_thread_destroy_domain_tls (domain);
1937                 domain->tlsrec_list = NULL;
1938         }
1939
1940         mono_reflection_cleanup_domain (domain);
1941
1942         if (domain->type_hash) {
1943                 mono_g_hash_table_destroy (domain->type_hash);
1944                 domain->type_hash = NULL;
1945         }
1946         if (domain->type_init_exception_hash) {
1947                 mono_g_hash_table_destroy (domain->type_init_exception_hash);
1948                 domain->type_init_exception_hash = NULL;
1949         }
1950
1951         if (domain->class_vtable_array) {
1952                 int i;
1953                 for (i = 0; i < domain->class_vtable_array->len; ++i)
1954                         unregister_vtable_reflection_type (g_ptr_array_index (domain->class_vtable_array, i));
1955         }
1956
1957         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1958                 MonoAssembly *ass = tmp->data;
1959                 mono_assembly_release_gc_roots (ass);
1960         }
1961
1962         /* This needs to be done before closing assemblies */
1963         mono_gc_clear_domain (domain);
1964
1965         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1966                 MonoAssembly *ass = tmp->data;
1967                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading domain %s[%p], assembly %s[%p], ref_count=%d", domain->friendly_name, domain, ass->aname.name, ass, ass->ref_count);
1968                 if (!mono_assembly_close_except_image_pools (ass))
1969                         tmp->data = NULL;
1970         }
1971
1972         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1973                 MonoAssembly *ass = tmp->data;
1974                 if (ass)
1975                         mono_assembly_close_finish (ass);
1976         }
1977         g_slist_free (domain->domain_assemblies);
1978         domain->domain_assemblies = NULL;
1979
1980         /* 
1981          * Send this after the assemblies have been unloaded and the domain is still in a 
1982          * usable state.
1983          */
1984         mono_profiler_appdomain_event (domain, MONO_PROFILE_END_UNLOAD);
1985
1986         if (free_domain_hook)
1987                 free_domain_hook (domain);
1988
1989         /* FIXME: free delegate_hash_table when it's used */
1990         if (domain->search_path) {
1991                 g_strfreev (domain->search_path);
1992                 domain->search_path = NULL;
1993         }
1994         domain->create_proxy_for_type_method = NULL;
1995         domain->private_invoke_method = NULL;
1996         domain->default_context = NULL;
1997         domain->out_of_memory_ex = NULL;
1998         domain->null_reference_ex = NULL;
1999         domain->stack_overflow_ex = NULL;
2000         domain->ephemeron_tombstone = NULL;
2001         domain->entry_assembly = NULL;
2002
2003         g_free (domain->friendly_name);
2004         domain->friendly_name = NULL;
2005         g_ptr_array_free (domain->class_vtable_array, TRUE);
2006         domain->class_vtable_array = NULL;
2007         g_hash_table_destroy (domain->proxy_vtable_hash);
2008         domain->proxy_vtable_hash = NULL;
2009         if (domain->static_data_array) {
2010                 mono_gc_free_fixed (domain->static_data_array);
2011                 domain->static_data_array = NULL;
2012         }
2013         mono_internal_hash_table_destroy (&domain->jit_code_hash);
2014
2015         /*
2016          * There might still be jit info tables of this domain which
2017          * are not freed.  Since the domain cannot be in use anymore,
2018          * this will free them.
2019          */
2020         mono_thread_hazardous_try_free_all ();
2021         g_assert (domain->num_jit_info_tables == 1);
2022         jit_info_table_free (domain->jit_info_table);
2023         domain->jit_info_table = NULL;
2024         g_assert (!domain->jit_info_free_queue);
2025
2026         /* collect statistics */
2027         code_alloc = mono_code_manager_size (domain->code_mp, &code_size);
2028         total_domain_code_alloc += code_alloc;
2029         max_domain_code_alloc = MAX (max_domain_code_alloc, code_alloc);
2030         max_domain_code_size = MAX (max_domain_code_size, code_size);
2031
2032 #ifdef DEBUG_DOMAIN_UNLOAD
2033         mono_mempool_invalidate (domain->mp);
2034         mono_code_manager_invalidate (domain->code_mp);
2035 #else
2036         mono_perfcounters->loader_bytes -= mono_mempool_get_allocated (domain->mp);
2037         mono_mempool_destroy (domain->mp);
2038         domain->mp = NULL;
2039         mono_code_manager_destroy (domain->code_mp);
2040         domain->code_mp = NULL;
2041 #endif  
2042
2043         g_hash_table_destroy (domain->finalizable_objects_hash);
2044         domain->finalizable_objects_hash = NULL;
2045         if (domain->track_resurrection_objects_hash) {
2046                 g_hash_table_foreach (domain->track_resurrection_objects_hash, free_slist, NULL);
2047                 g_hash_table_destroy (domain->track_resurrection_objects_hash);
2048         }
2049         if (domain->track_resurrection_handles_hash)
2050                 g_hash_table_destroy (domain->track_resurrection_handles_hash);
2051         if (domain->method_rgctx_hash) {
2052                 g_hash_table_destroy (domain->method_rgctx_hash);
2053                 domain->method_rgctx_hash = NULL;
2054         }
2055         if (domain->generic_virtual_cases) {
2056                 g_hash_table_destroy (domain->generic_virtual_cases);
2057                 domain->generic_virtual_cases = NULL;
2058         }
2059         if (domain->generic_virtual_thunks) {
2060                 g_hash_table_destroy (domain->generic_virtual_thunks);
2061                 domain->generic_virtual_thunks = NULL;
2062         }
2063         if (domain->ftnptrs_hash) {
2064                 g_hash_table_destroy (domain->ftnptrs_hash);
2065                 domain->ftnptrs_hash = NULL;
2066         }
2067
2068         DeleteCriticalSection (&domain->finalizable_objects_hash_lock);
2069         DeleteCriticalSection (&domain->assemblies_lock);
2070         DeleteCriticalSection (&domain->jit_code_hash_lock);
2071         DeleteCriticalSection (&domain->lock);
2072         domain->setup = NULL;
2073
2074         mono_gc_deregister_root ((char*)&(domain->MONO_DOMAIN_FIRST_GC_TRACKED));
2075
2076         /* FIXME: anything else required ? */
2077
2078         mono_gc_free_fixed (domain);
2079
2080         mono_perfcounters->loader_appdomains--;
2081
2082         if (domain == mono_root_domain)
2083                 mono_root_domain = NULL;
2084 }
2085
2086 /**
2087  * mono_domain_get_id:
2088  * @domainid: the ID
2089  *
2090  * Returns: the a domain for a specific domain id.
2091  */
2092 MonoDomain * 
2093 mono_domain_get_by_id (gint32 domainid) 
2094 {
2095         MonoDomain * domain;
2096
2097         mono_appdomains_lock ();
2098         if (domainid < appdomain_list_size)
2099                 domain = appdomains_list [domainid];
2100         else
2101                 domain = NULL;
2102         mono_appdomains_unlock ();
2103
2104         return domain;
2105 }
2106
2107 gint32
2108 mono_domain_get_id (MonoDomain *domain)
2109 {
2110         return domain->domain_id;
2111 }
2112
2113 /*
2114  * mono_domain_alloc:
2115  *
2116  * LOCKING: Acquires the domain lock.
2117  */
2118 gpointer
2119 mono_domain_alloc (MonoDomain *domain, guint size)
2120 {
2121         gpointer res;
2122
2123         mono_domain_lock (domain);
2124         mono_perfcounters->loader_bytes += size;
2125         res = mono_mempool_alloc (domain->mp, size);
2126         mono_domain_unlock (domain);
2127
2128         return res;
2129 }
2130
2131 /*
2132  * mono_domain_alloc0:
2133  *
2134  * LOCKING: Acquires the domain lock.
2135  */
2136 gpointer
2137 mono_domain_alloc0 (MonoDomain *domain, guint size)
2138 {
2139         gpointer res;
2140
2141         mono_domain_lock (domain);
2142         mono_perfcounters->loader_bytes += size;
2143         res = mono_mempool_alloc0 (domain->mp, size);
2144         mono_domain_unlock (domain);
2145
2146         return res;
2147 }
2148
2149 /*
2150  * mono_domain_code_reserve:
2151  *
2152  * LOCKING: Acquires the domain lock.
2153  */
2154 void*
2155 mono_domain_code_reserve (MonoDomain *domain, int size)
2156 {
2157         gpointer res;
2158
2159         mono_domain_lock (domain);
2160         res = mono_code_manager_reserve (domain->code_mp, size);
2161         mono_domain_unlock (domain);
2162
2163         return res;
2164 }
2165
2166 /*
2167  * mono_domain_code_reserve_align:
2168  *
2169  * LOCKING: Acquires the domain lock.
2170  */
2171 void*
2172 mono_domain_code_reserve_align (MonoDomain *domain, int size, int alignment)
2173 {
2174         gpointer res;
2175
2176         mono_domain_lock (domain);
2177         res = mono_code_manager_reserve_align (domain->code_mp, size, alignment);
2178         mono_domain_unlock (domain);
2179
2180         return res;
2181 }
2182
2183 /*
2184  * mono_domain_code_commit:
2185  *
2186  * LOCKING: Acquires the domain lock.
2187  */
2188 void
2189 mono_domain_code_commit (MonoDomain *domain, void *data, int size, int newsize)
2190 {
2191         mono_domain_lock (domain);
2192         mono_code_manager_commit (domain->code_mp, data, size, newsize);
2193         mono_domain_unlock (domain);
2194 }
2195
2196 #if defined(__native_client_codegen__) && defined(__native_client__)
2197 /*
2198  * Given the temporary buffer (allocated by mono_domain_code_reserve) into which
2199  * we are generating code, return a pointer to the destination in the dynamic 
2200  * code segment into which the code will be copied when mono_domain_code_commit
2201  * is called.
2202  * LOCKING: Acquires the domain lock.
2203  */
2204 void *
2205 nacl_domain_get_code_dest (MonoDomain *domain, void *data)
2206 {
2207         void *dest;
2208         mono_domain_lock (domain);
2209         dest = nacl_code_manager_get_code_dest (domain->code_mp, data);
2210         mono_domain_unlock (domain);
2211         return dest;
2212 }
2213
2214 /* 
2215  * Convenience function which calls mono_domain_code_commit to validate and copy
2216  * the code. The caller sets *buf_base and *buf_size to the start and size of
2217  * the buffer (allocated by mono_domain_code_reserve), and *code_end to the byte
2218  * after the last instruction byte. On return, *buf_base will point to the start
2219  * of the copied in the code segment, and *code_end will point after the end of 
2220  * the copied code.
2221  */
2222 void
2223 nacl_domain_code_validate (MonoDomain *domain, guint8 **buf_base, int buf_size, guint8 **code_end)
2224 {
2225         guint8 *tmp = nacl_domain_get_code_dest (domain, *buf_base);
2226         mono_domain_code_commit (domain, *buf_base, buf_size, *code_end - *buf_base);
2227         *code_end = tmp + (*code_end - *buf_base);
2228         *buf_base = tmp;
2229 }
2230
2231 #else
2232
2233 /* no-op versions of Native Client functions */
2234
2235 void *
2236 nacl_domain_get_code_dest (MonoDomain *domain, void *data)
2237 {
2238         return data;
2239 }
2240
2241 void
2242 nacl_domain_code_validate (MonoDomain *domain, guint8 **buf_base, int buf_size, guint8 **code_end)
2243 {
2244 }
2245
2246 #endif
2247
2248 /*
2249  * mono_domain_code_foreach:
2250  * Iterate over the code thunks of the code manager of @domain.
2251  * 
2252  * The @func callback MUST not take any locks. If it really needs to, it must respect
2253  * the locking rules of the runtime: http://www.mono-project.com/Mono:Runtime:Documentation:ThreadSafety 
2254  * LOCKING: Acquires the domain lock.
2255  */
2256
2257 void
2258 mono_domain_code_foreach (MonoDomain *domain, MonoCodeManagerFunc func, void *user_data)
2259 {
2260         mono_domain_lock (domain);
2261         mono_code_manager_foreach (domain->code_mp, func, user_data);
2262         mono_domain_unlock (domain);
2263 }
2264
2265
2266 void 
2267 mono_context_set (MonoAppContext * new_context)
2268 {
2269         SET_APPCONTEXT (new_context);
2270 }
2271
2272 MonoAppContext * 
2273 mono_context_get (void)
2274 {
2275         return GET_APPCONTEXT ();
2276 }
2277
2278 /* LOCKING: the caller holds the lock for this domain */
2279 void
2280 mono_domain_add_class_static_data (MonoDomain *domain, MonoClass *klass, gpointer data, guint32 *bitmap)
2281 {
2282         /* The first entry in the array is the index of the next free slot
2283          * and the total size of the array
2284          */
2285         int next;
2286         if (domain->static_data_array) {
2287                 int size = GPOINTER_TO_INT (domain->static_data_array [1]);
2288                 next = GPOINTER_TO_INT (domain->static_data_array [0]);
2289                 if (next >= size) {
2290                         /* 'data' is allocated by alloc_fixed */
2291                         gpointer *new_array = mono_gc_alloc_fixed (sizeof (gpointer) * (size * 2), MONO_GC_ROOT_DESCR_FOR_FIXED (size * 2));
2292                         mono_gc_memmove (new_array, domain->static_data_array, sizeof (gpointer) * size);
2293                         size *= 2;
2294                         new_array [1] = GINT_TO_POINTER (size);
2295                         mono_gc_free_fixed (domain->static_data_array);
2296                         domain->static_data_array = new_array;
2297                 }
2298         } else {
2299                 int size = 32;
2300                 gpointer *new_array = mono_gc_alloc_fixed (sizeof (gpointer) * size, MONO_GC_ROOT_DESCR_FOR_FIXED (size));
2301                 next = 2;
2302                 new_array [0] = GINT_TO_POINTER (next);
2303                 new_array [1] = GINT_TO_POINTER (size);
2304                 domain->static_data_array = new_array;
2305         }
2306         domain->static_data_array [next++] = data;
2307         domain->static_data_array [0] = GINT_TO_POINTER (next);
2308 }
2309
2310 MonoImage*
2311 mono_get_corlib (void)
2312 {
2313         return mono_defaults.corlib;
2314 }
2315
2316 MonoClass*
2317 mono_get_object_class (void)
2318 {
2319         return mono_defaults.object_class;
2320 }
2321
2322 MonoClass*
2323 mono_get_byte_class (void)
2324 {
2325         return mono_defaults.byte_class;
2326 }
2327
2328 MonoClass*
2329 mono_get_void_class (void)
2330 {
2331         return mono_defaults.void_class;
2332 }
2333
2334 MonoClass*
2335 mono_get_boolean_class (void)
2336 {
2337         return mono_defaults.boolean_class;
2338 }
2339
2340 MonoClass*
2341 mono_get_sbyte_class (void)
2342 {
2343         return mono_defaults.sbyte_class;
2344 }
2345
2346 MonoClass*
2347 mono_get_int16_class (void)
2348 {
2349         return mono_defaults.int16_class;
2350 }
2351
2352 MonoClass*
2353 mono_get_uint16_class (void)
2354 {
2355         return mono_defaults.uint16_class;
2356 }
2357
2358 MonoClass*
2359 mono_get_int32_class (void)
2360 {
2361         return mono_defaults.int32_class;
2362 }
2363
2364 MonoClass*
2365 mono_get_uint32_class (void)
2366 {
2367         return mono_defaults.uint32_class;
2368 }
2369
2370 MonoClass*
2371 mono_get_intptr_class (void)
2372 {
2373         return mono_defaults.int_class;
2374 }
2375
2376 MonoClass*
2377 mono_get_uintptr_class (void)
2378 {
2379         return mono_defaults.uint_class;
2380 }
2381
2382 MonoClass*
2383 mono_get_int64_class (void)
2384 {
2385         return mono_defaults.int64_class;
2386 }
2387
2388 MonoClass*
2389 mono_get_uint64_class (void)
2390 {
2391         return mono_defaults.uint64_class;
2392 }
2393
2394 MonoClass*
2395 mono_get_single_class (void)
2396 {
2397         return mono_defaults.single_class;
2398 }
2399
2400 MonoClass*
2401 mono_get_double_class (void)
2402 {
2403         return mono_defaults.double_class;
2404 }
2405
2406 MonoClass*
2407 mono_get_char_class (void)
2408 {
2409         return mono_defaults.char_class;
2410 }
2411
2412 MonoClass*
2413 mono_get_string_class (void)
2414 {
2415         return mono_defaults.string_class;
2416 }
2417
2418 MonoClass*
2419 mono_get_enum_class (void)
2420 {
2421         return mono_defaults.enum_class;
2422 }
2423
2424 MonoClass*
2425 mono_get_array_class (void)
2426 {
2427         return mono_defaults.array_class;
2428 }
2429
2430 MonoClass*
2431 mono_get_thread_class (void)
2432 {
2433         return mono_defaults.thread_class;
2434 }
2435
2436 MonoClass*
2437 mono_get_exception_class (void)
2438 {
2439         return mono_defaults.exception_class;
2440 }
2441
2442
2443 static char* get_attribute_value (const gchar **attribute_names, 
2444                                         const gchar **attribute_values, 
2445                                         const char *att_name)
2446 {
2447         int n;
2448         for (n=0; attribute_names[n] != NULL; n++) {
2449                 if (strcmp (attribute_names[n], att_name) == 0)
2450                         return g_strdup (attribute_values[n]);
2451         }
2452         return NULL;
2453 }
2454
2455 static void start_element (GMarkupParseContext *context, 
2456                            const gchar         *element_name,
2457                            const gchar        **attribute_names,
2458                            const gchar        **attribute_values,
2459                            gpointer             user_data,
2460                            GError             **error)
2461 {
2462         AppConfigInfo* app_config = (AppConfigInfo*) user_data;
2463         
2464         if (strcmp (element_name, "configuration") == 0) {
2465                 app_config->configuration_count++;
2466                 return;
2467         }
2468         if (strcmp (element_name, "startup") == 0) {
2469                 app_config->startup_count++;
2470                 return;
2471         }
2472         
2473         if (app_config->configuration_count != 1 || app_config->startup_count != 1)
2474                 return;
2475         
2476         if (strcmp (element_name, "requiredRuntime") == 0) {
2477                 app_config->required_runtime = get_attribute_value (attribute_names, attribute_values, "version");
2478         } else if (strcmp (element_name, "supportedRuntime") == 0) {
2479                 char *version = get_attribute_value (attribute_names, attribute_values, "version");
2480                 app_config->supported_runtimes = g_slist_append (app_config->supported_runtimes, version);
2481         }
2482 }
2483
2484 static void end_element   (GMarkupParseContext *context,
2485                            const gchar         *element_name,
2486                            gpointer             user_data,
2487                            GError             **error)
2488 {
2489         AppConfigInfo* app_config = (AppConfigInfo*) user_data;
2490         
2491         if (strcmp (element_name, "configuration") == 0) {
2492                 app_config->configuration_count--;
2493         } else if (strcmp (element_name, "startup") == 0) {
2494                 app_config->startup_count--;
2495         }
2496 }
2497
2498 static const GMarkupParser 
2499 mono_parser = {
2500         start_element,
2501         end_element,
2502         NULL,
2503         NULL,
2504         NULL
2505 };
2506
2507 static AppConfigInfo *
2508 app_config_parse (const char *exe_filename)
2509 {
2510         AppConfigInfo *app_config;
2511         GMarkupParseContext *context;
2512         char *text;
2513         gsize len;
2514         const char *bundled_config;
2515         char *config_filename;
2516
2517         bundled_config = mono_config_string_for_assembly_file (exe_filename);
2518
2519         if (bundled_config) {
2520                 text = g_strdup (bundled_config);
2521                 len = strlen (text);
2522         } else {
2523                 config_filename = g_strconcat (exe_filename, ".config", NULL);
2524
2525                 if (!g_file_get_contents (config_filename, &text, &len, NULL)) {
2526                         g_free (config_filename);
2527                         return NULL;
2528                 }
2529                 g_free (config_filename);
2530         }
2531
2532         app_config = g_new0 (AppConfigInfo, 1);
2533
2534         context = g_markup_parse_context_new (&mono_parser, 0, app_config, NULL);
2535         if (g_markup_parse_context_parse (context, text, len, NULL)) {
2536                 g_markup_parse_context_end_parse (context, NULL);
2537         }
2538         g_markup_parse_context_free (context);
2539         g_free (text);
2540         return app_config;
2541 }
2542
2543 static void 
2544 app_config_free (AppConfigInfo* app_config)
2545 {
2546         char *rt;
2547         GSList *list = app_config->supported_runtimes;
2548         while (list != NULL) {
2549                 rt = (char*)list->data;
2550                 g_free (rt);
2551                 list = g_slist_next (list);
2552         }
2553         g_slist_free (app_config->supported_runtimes);
2554         g_free (app_config->required_runtime);
2555         g_free (app_config);
2556 }
2557
2558
2559 static const MonoRuntimeInfo*
2560 get_runtime_by_version (const char *version)
2561 {
2562         int n;
2563         int max = G_N_ELEMENTS (supported_runtimes);
2564         int vlen;
2565
2566         if (!version)
2567                 return NULL;
2568
2569         for (n=0; n<max; n++) {
2570                 if (strcmp (version, supported_runtimes[n].runtime_version) == 0)
2571                         return &supported_runtimes[n];
2572         }
2573         
2574         vlen = strlen (version);
2575         if (vlen >= 4 && version [1] - '0' >= 4) {
2576                 for (n=0; n<max; n++) {
2577                         if (strncmp (version, supported_runtimes[n].runtime_version, 4) == 0)
2578                                 return &supported_runtimes[n];
2579                 }
2580         }
2581         
2582         return NULL;
2583 }
2584
2585 static void
2586 get_runtimes_from_exe (const char *exe_file, MonoImage **exe_image, const MonoRuntimeInfo** runtimes)
2587 {
2588         AppConfigInfo* app_config;
2589         char *version;
2590         const MonoRuntimeInfo* runtime = NULL;
2591         MonoImage *image = NULL;
2592         
2593         app_config = app_config_parse (exe_file);
2594         
2595         if (app_config != NULL) {
2596                 /* Check supportedRuntime elements, if none is supported, fail.
2597                  * If there are no such elements, look for a requiredRuntime element.
2598                  */
2599                 if (app_config->supported_runtimes != NULL) {
2600                         int n = 0;
2601                         GSList *list = app_config->supported_runtimes;
2602                         while (list != NULL) {
2603                                 version = (char*) list->data;
2604                                 runtime = get_runtime_by_version (version);
2605                                 if (runtime != NULL)
2606                                         runtimes [n++] = runtime;
2607                                 list = g_slist_next (list);
2608                         }
2609                         runtimes [n] = NULL;
2610                         app_config_free (app_config);
2611                         return;
2612                 }
2613                 
2614                 /* Check the requiredRuntime element. This is for 1.0 apps only. */
2615                 if (app_config->required_runtime != NULL) {
2616                         runtimes [0] = get_runtime_by_version (app_config->required_runtime);
2617                         runtimes [1] = NULL;
2618                         app_config_free (app_config);
2619                         return;
2620                 }
2621                 app_config_free (app_config);
2622         }
2623         
2624         /* Look for a runtime with the exact version */
2625         image = mono_assembly_open_from_bundle (exe_file, NULL, FALSE);
2626
2627         if (image == NULL)
2628                 image = mono_image_open (exe_file, NULL);
2629
2630         if (image == NULL) {
2631                 /* The image is wrong or the file was not found. In this case return
2632                  * a default runtime and leave to the initialization method the work of
2633                  * reporting the error.
2634                  */
2635                 runtimes [0] = get_runtime_by_version (DEFAULT_RUNTIME_VERSION);
2636                 runtimes [1] = NULL;
2637                 return;
2638         }
2639
2640         *exe_image = image;
2641
2642         runtimes [0] = get_runtime_by_version (image->version);
2643         runtimes [1] = NULL;
2644 }
2645
2646
2647 /**
2648  * mono_get_runtime_info:
2649  *
2650  * Returns: the version of the current runtime instance.
2651  */
2652 const MonoRuntimeInfo*
2653 mono_get_runtime_info (void)
2654 {
2655         return current_runtime;
2656 }
2657
2658 gchar *
2659 mono_debugger_check_runtime_version (const char *filename)
2660 {
2661         const MonoRuntimeInfo* runtimes [G_N_ELEMENTS (supported_runtimes) + 1];
2662         const MonoRuntimeInfo *rinfo;
2663         MonoImage *image;
2664
2665         get_runtimes_from_exe (filename, &image, runtimes);
2666         rinfo = runtimes [0];
2667
2668         if (!rinfo)
2669                 return g_strdup_printf ("Cannot get runtime version from assembly `%s'", filename);
2670
2671         if (rinfo != current_runtime)
2672                 return g_strdup_printf ("The Mono Debugger is currently using the `%s' runtime, but "
2673                                         "the assembly `%s' requires version `%s'", current_runtime->runtime_version,
2674                                         filename, rinfo->runtime_version);
2675
2676         return NULL;
2677 }
2678
2679 /**
2680  * mono_framework_version:
2681  *
2682  * Return the major version of the framework curently executing.
2683  */
2684 int
2685 mono_framework_version (void)
2686 {
2687         return current_runtime->framework_version [0] - '0';
2688 }
2689