Merge remote-tracking branch 'local/msvc-updates' into msvc-updates
[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 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         /* This needs to be done before closing assemblies */
1958         mono_gc_clear_domain (domain);
1959
1960         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1961                 MonoAssembly *ass = tmp->data;
1962                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading domain %s[%p], assembly %s[%p], ref_count=%d\n", domain->friendly_name, domain, ass->aname.name, ass, ass->ref_count);
1963                 if (!mono_assembly_close_except_image_pools (ass))
1964                         tmp->data = NULL;
1965         }
1966
1967         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1968                 MonoAssembly *ass = tmp->data;
1969                 if (ass)
1970                         mono_assembly_close_finish (ass);
1971         }
1972         g_slist_free (domain->domain_assemblies);
1973         domain->domain_assemblies = NULL;
1974
1975         /* 
1976          * Send this after the assemblies have been unloaded and the domain is still in a 
1977          * usable state.
1978          */
1979         mono_profiler_appdomain_event (domain, MONO_PROFILE_END_UNLOAD);
1980
1981         if (free_domain_hook)
1982                 free_domain_hook (domain);
1983
1984         /* FIXME: free delegate_hash_table when it's used */
1985         if (domain->search_path) {
1986                 g_strfreev (domain->search_path);
1987                 domain->search_path = NULL;
1988         }
1989         domain->create_proxy_for_type_method = NULL;
1990         domain->private_invoke_method = NULL;
1991         domain->default_context = NULL;
1992         domain->out_of_memory_ex = NULL;
1993         domain->null_reference_ex = NULL;
1994         domain->stack_overflow_ex = NULL;
1995         domain->ephemeron_tombstone = NULL;
1996         domain->entry_assembly = NULL;
1997
1998         g_free (domain->friendly_name);
1999         domain->friendly_name = NULL;
2000         g_ptr_array_free (domain->class_vtable_array, TRUE);
2001         domain->class_vtable_array = NULL;
2002         g_hash_table_destroy (domain->proxy_vtable_hash);
2003         domain->proxy_vtable_hash = NULL;
2004         if (domain->static_data_array) {
2005                 mono_gc_free_fixed (domain->static_data_array);
2006                 domain->static_data_array = NULL;
2007         }
2008         mono_internal_hash_table_destroy (&domain->jit_code_hash);
2009
2010         /*
2011          * There might still be jit info tables of this domain which
2012          * are not freed.  Since the domain cannot be in use anymore,
2013          * this will free them.
2014          */
2015         mono_thread_hazardous_try_free_all ();
2016         g_assert (domain->num_jit_info_tables == 1);
2017         jit_info_table_free (domain->jit_info_table);
2018         domain->jit_info_table = NULL;
2019         g_assert (!domain->jit_info_free_queue);
2020
2021         /* collect statistics */
2022         code_alloc = mono_code_manager_size (domain->code_mp, &code_size);
2023         total_domain_code_alloc += code_alloc;
2024         max_domain_code_alloc = MAX (max_domain_code_alloc, code_alloc);
2025         max_domain_code_size = MAX (max_domain_code_size, code_size);
2026
2027 #ifdef DEBUG_DOMAIN_UNLOAD
2028         mono_mempool_invalidate (domain->mp);
2029         mono_code_manager_invalidate (domain->code_mp);
2030 #else
2031         mono_perfcounters->loader_bytes -= mono_mempool_get_allocated (domain->mp);
2032         mono_mempool_destroy (domain->mp);
2033         domain->mp = NULL;
2034         mono_code_manager_destroy (domain->code_mp);
2035         domain->code_mp = NULL;
2036 #endif  
2037
2038         g_hash_table_destroy (domain->finalizable_objects_hash);
2039         domain->finalizable_objects_hash = NULL;
2040         if (domain->track_resurrection_objects_hash) {
2041                 g_hash_table_foreach (domain->track_resurrection_objects_hash, free_slist, NULL);
2042                 g_hash_table_destroy (domain->track_resurrection_objects_hash);
2043         }
2044         if (domain->track_resurrection_handles_hash)
2045                 g_hash_table_destroy (domain->track_resurrection_handles_hash);
2046         if (domain->method_rgctx_hash) {
2047                 g_hash_table_destroy (domain->method_rgctx_hash);
2048                 domain->method_rgctx_hash = NULL;
2049         }
2050         if (domain->generic_virtual_cases) {
2051                 g_hash_table_destroy (domain->generic_virtual_cases);
2052                 domain->generic_virtual_cases = NULL;
2053         }
2054         if (domain->generic_virtual_thunks) {
2055                 g_hash_table_destroy (domain->generic_virtual_thunks);
2056                 domain->generic_virtual_thunks = NULL;
2057         }
2058         if (domain->ftnptrs_hash) {
2059                 g_hash_table_destroy (domain->ftnptrs_hash);
2060                 domain->ftnptrs_hash = NULL;
2061         }
2062
2063         DeleteCriticalSection (&domain->finalizable_objects_hash_lock);
2064         DeleteCriticalSection (&domain->assemblies_lock);
2065         DeleteCriticalSection (&domain->jit_code_hash_lock);
2066         DeleteCriticalSection (&domain->lock);
2067         domain->setup = NULL;
2068
2069         mono_gc_deregister_root ((char*)&(domain->MONO_DOMAIN_FIRST_GC_TRACKED));
2070
2071         /* FIXME: anything else required ? */
2072
2073         mono_gc_free_fixed (domain);
2074
2075         mono_perfcounters->loader_appdomains--;
2076
2077         if (domain == mono_root_domain)
2078                 mono_root_domain = NULL;
2079 }
2080
2081 /**
2082  * mono_domain_get_id:
2083  * @domainid: the ID
2084  *
2085  * Returns: the a domain for a specific domain id.
2086  */
2087 MonoDomain * 
2088 mono_domain_get_by_id (gint32 domainid) 
2089 {
2090         MonoDomain * domain;
2091
2092         mono_appdomains_lock ();
2093         if (domainid < appdomain_list_size)
2094                 domain = appdomains_list [domainid];
2095         else
2096                 domain = NULL;
2097         mono_appdomains_unlock ();
2098
2099         return domain;
2100 }
2101
2102 gint32
2103 mono_domain_get_id (MonoDomain *domain)
2104 {
2105         return domain->domain_id;
2106 }
2107
2108 /*
2109  * mono_domain_alloc:
2110  *
2111  * LOCKING: Acquires the domain lock.
2112  */
2113 gpointer
2114 mono_domain_alloc (MonoDomain *domain, guint size)
2115 {
2116         gpointer res;
2117
2118         mono_domain_lock (domain);
2119         mono_perfcounters->loader_bytes += size;
2120         res = mono_mempool_alloc (domain->mp, size);
2121         mono_domain_unlock (domain);
2122
2123         return res;
2124 }
2125
2126 /*
2127  * mono_domain_alloc0:
2128  *
2129  * LOCKING: Acquires the domain lock.
2130  */
2131 gpointer
2132 mono_domain_alloc0 (MonoDomain *domain, guint size)
2133 {
2134         gpointer res;
2135
2136         mono_domain_lock (domain);
2137         mono_perfcounters->loader_bytes += size;
2138         res = mono_mempool_alloc0 (domain->mp, size);
2139         mono_domain_unlock (domain);
2140
2141         return res;
2142 }
2143
2144 /*
2145  * mono_domain_code_reserve:
2146  *
2147  * LOCKING: Acquires the domain lock.
2148  */
2149 void*
2150 mono_domain_code_reserve (MonoDomain *domain, int size)
2151 {
2152         gpointer res;
2153
2154         mono_domain_lock (domain);
2155         res = mono_code_manager_reserve (domain->code_mp, size);
2156         mono_domain_unlock (domain);
2157
2158         return res;
2159 }
2160
2161 /*
2162  * mono_domain_code_reserve_align:
2163  *
2164  * LOCKING: Acquires the domain lock.
2165  */
2166 void*
2167 mono_domain_code_reserve_align (MonoDomain *domain, int size, int alignment)
2168 {
2169         gpointer res;
2170
2171         mono_domain_lock (domain);
2172         res = mono_code_manager_reserve_align (domain->code_mp, size, alignment);
2173         mono_domain_unlock (domain);
2174
2175         return res;
2176 }
2177
2178 /*
2179  * mono_domain_code_commit:
2180  *
2181  * LOCKING: Acquires the domain lock.
2182  */
2183 void
2184 mono_domain_code_commit (MonoDomain *domain, void *data, int size, int newsize)
2185 {
2186         mono_domain_lock (domain);
2187         mono_code_manager_commit (domain->code_mp, data, size, newsize);
2188         mono_domain_unlock (domain);
2189 }
2190
2191 #if defined(__native_client_codegen__) && defined(__native_client__)
2192 /*
2193  * Given the temporary buffer (allocated by mono_domain_code_reserve) into which
2194  * we are generating code, return a pointer to the destination in the dynamic 
2195  * code segment into which the code will be copied when mono_domain_code_commit
2196  * is called.
2197  * LOCKING: Acquires the domain lock.
2198  */
2199 void *
2200 nacl_domain_get_code_dest (MonoDomain *domain, void *data)
2201 {
2202         void *dest;
2203         mono_domain_lock (domain);
2204         dest = nacl_code_manager_get_code_dest (domain->code_mp, data);
2205         mono_domain_unlock (domain);
2206         return dest;
2207 }
2208
2209 /* 
2210  * Convenience function which calls mono_domain_code_commit to validate and copy
2211  * the code. The caller sets *buf_base and *buf_size to the start and size of
2212  * the buffer (allocated by mono_domain_code_reserve), and *code_end to the byte
2213  * after the last instruction byte. On return, *buf_base will point to the start
2214  * of the copied in the code segment, and *code_end will point after the end of 
2215  * the copied code.
2216  */
2217 void
2218 nacl_domain_code_validate (MonoDomain *domain, guint8 **buf_base, int buf_size, guint8 **code_end)
2219 {
2220         guint8 *tmp = nacl_domain_get_code_dest (domain, *buf_base);
2221         mono_domain_code_commit (domain, *buf_base, buf_size, *code_end - *buf_base);
2222         *code_end = tmp + (*code_end - *buf_base);
2223         *buf_base = tmp;
2224 }
2225
2226 #else
2227
2228 /* no-op versions of Native Client functions */
2229
2230 void *
2231 nacl_domain_get_code_dest (MonoDomain *domain, void *data)
2232 {
2233         return data;
2234 }
2235
2236 void
2237 nacl_domain_code_validate (MonoDomain *domain, guint8 **buf_base, int buf_size, guint8 **code_end)
2238 {
2239 }
2240
2241 #endif
2242
2243 /*
2244  * mono_domain_code_foreach:
2245  * Iterate over the code thunks of the code manager of @domain.
2246  * 
2247  * The @func callback MUST not take any locks. If it really needs to, it must respect
2248  * the locking rules of the runtime: http://www.mono-project.com/Mono:Runtime:Documentation:ThreadSafety 
2249  * LOCKING: Acquires the domain lock.
2250  */
2251
2252 void
2253 mono_domain_code_foreach (MonoDomain *domain, MonoCodeManagerFunc func, void *user_data)
2254 {
2255         mono_domain_lock (domain);
2256         mono_code_manager_foreach (domain->code_mp, func, user_data);
2257         mono_domain_unlock (domain);
2258 }
2259
2260
2261 void 
2262 mono_context_set (MonoAppContext * new_context)
2263 {
2264         SET_APPCONTEXT (new_context);
2265 }
2266
2267 MonoAppContext * 
2268 mono_context_get (void)
2269 {
2270         return GET_APPCONTEXT ();
2271 }
2272
2273 /* LOCKING: the caller holds the lock for this domain */
2274 void
2275 mono_domain_add_class_static_data (MonoDomain *domain, MonoClass *klass, gpointer data, guint32 *bitmap)
2276 {
2277         /* The first entry in the array is the index of the next free slot
2278          * and the total size of the array
2279          */
2280         int next;
2281         if (domain->static_data_array) {
2282                 int size = GPOINTER_TO_INT (domain->static_data_array [1]);
2283                 next = GPOINTER_TO_INT (domain->static_data_array [0]);
2284                 if (next >= size) {
2285                         /* 'data' is allocated by alloc_fixed */
2286                         gpointer *new_array = mono_gc_alloc_fixed (sizeof (gpointer) * (size * 2), MONO_GC_ROOT_DESCR_FOR_FIXED (size * 2));
2287                         mono_gc_memmove (new_array, domain->static_data_array, sizeof (gpointer) * size);
2288                         size *= 2;
2289                         new_array [1] = GINT_TO_POINTER (size);
2290                         mono_gc_free_fixed (domain->static_data_array);
2291                         domain->static_data_array = new_array;
2292                 }
2293         } else {
2294                 int size = 32;
2295                 gpointer *new_array = mono_gc_alloc_fixed (sizeof (gpointer) * size, MONO_GC_ROOT_DESCR_FOR_FIXED (size));
2296                 next = 2;
2297                 new_array [0] = GINT_TO_POINTER (next);
2298                 new_array [1] = GINT_TO_POINTER (size);
2299                 domain->static_data_array = new_array;
2300         }
2301         domain->static_data_array [next++] = data;
2302         domain->static_data_array [0] = GINT_TO_POINTER (next);
2303 }
2304
2305 MonoImage*
2306 mono_get_corlib (void)
2307 {
2308         return mono_defaults.corlib;
2309 }
2310
2311 MonoClass*
2312 mono_get_object_class (void)
2313 {
2314         return mono_defaults.object_class;
2315 }
2316
2317 MonoClass*
2318 mono_get_byte_class (void)
2319 {
2320         return mono_defaults.byte_class;
2321 }
2322
2323 MonoClass*
2324 mono_get_void_class (void)
2325 {
2326         return mono_defaults.void_class;
2327 }
2328
2329 MonoClass*
2330 mono_get_boolean_class (void)
2331 {
2332         return mono_defaults.boolean_class;
2333 }
2334
2335 MonoClass*
2336 mono_get_sbyte_class (void)
2337 {
2338         return mono_defaults.sbyte_class;
2339 }
2340
2341 MonoClass*
2342 mono_get_int16_class (void)
2343 {
2344         return mono_defaults.int16_class;
2345 }
2346
2347 MonoClass*
2348 mono_get_uint16_class (void)
2349 {
2350         return mono_defaults.uint16_class;
2351 }
2352
2353 MonoClass*
2354 mono_get_int32_class (void)
2355 {
2356         return mono_defaults.int32_class;
2357 }
2358
2359 MonoClass*
2360 mono_get_uint32_class (void)
2361 {
2362         return mono_defaults.uint32_class;
2363 }
2364
2365 MonoClass*
2366 mono_get_intptr_class (void)
2367 {
2368         return mono_defaults.int_class;
2369 }
2370
2371 MonoClass*
2372 mono_get_uintptr_class (void)
2373 {
2374         return mono_defaults.uint_class;
2375 }
2376
2377 MonoClass*
2378 mono_get_int64_class (void)
2379 {
2380         return mono_defaults.int64_class;
2381 }
2382
2383 MonoClass*
2384 mono_get_uint64_class (void)
2385 {
2386         return mono_defaults.uint64_class;
2387 }
2388
2389 MonoClass*
2390 mono_get_single_class (void)
2391 {
2392         return mono_defaults.single_class;
2393 }
2394
2395 MonoClass*
2396 mono_get_double_class (void)
2397 {
2398         return mono_defaults.double_class;
2399 }
2400
2401 MonoClass*
2402 mono_get_char_class (void)
2403 {
2404         return mono_defaults.char_class;
2405 }
2406
2407 MonoClass*
2408 mono_get_string_class (void)
2409 {
2410         return mono_defaults.string_class;
2411 }
2412
2413 MonoClass*
2414 mono_get_enum_class (void)
2415 {
2416         return mono_defaults.enum_class;
2417 }
2418
2419 MonoClass*
2420 mono_get_array_class (void)
2421 {
2422         return mono_defaults.array_class;
2423 }
2424
2425 MonoClass*
2426 mono_get_thread_class (void)
2427 {
2428         return mono_defaults.thread_class;
2429 }
2430
2431 MonoClass*
2432 mono_get_exception_class (void)
2433 {
2434         return mono_defaults.exception_class;
2435 }
2436
2437
2438 static char* get_attribute_value (const gchar **attribute_names, 
2439                                         const gchar **attribute_values, 
2440                                         const char *att_name)
2441 {
2442         int n;
2443         for (n=0; attribute_names[n] != NULL; n++) {
2444                 if (strcmp (attribute_names[n], att_name) == 0)
2445                         return g_strdup (attribute_values[n]);
2446         }
2447         return NULL;
2448 }
2449
2450 static void start_element (GMarkupParseContext *context, 
2451                            const gchar         *element_name,
2452                            const gchar        **attribute_names,
2453                            const gchar        **attribute_values,
2454                            gpointer             user_data,
2455                            GError             **error)
2456 {
2457         AppConfigInfo* app_config = (AppConfigInfo*) user_data;
2458         
2459         if (strcmp (element_name, "configuration") == 0) {
2460                 app_config->configuration_count++;
2461                 return;
2462         }
2463         if (strcmp (element_name, "startup") == 0) {
2464                 app_config->startup_count++;
2465                 return;
2466         }
2467         
2468         if (app_config->configuration_count != 1 || app_config->startup_count != 1)
2469                 return;
2470         
2471         if (strcmp (element_name, "requiredRuntime") == 0) {
2472                 app_config->required_runtime = get_attribute_value (attribute_names, attribute_values, "version");
2473         } else if (strcmp (element_name, "supportedRuntime") == 0) {
2474                 char *version = get_attribute_value (attribute_names, attribute_values, "version");
2475                 app_config->supported_runtimes = g_slist_append (app_config->supported_runtimes, version);
2476         }
2477 }
2478
2479 static void end_element   (GMarkupParseContext *context,
2480                            const gchar         *element_name,
2481                            gpointer             user_data,
2482                            GError             **error)
2483 {
2484         AppConfigInfo* app_config = (AppConfigInfo*) user_data;
2485         
2486         if (strcmp (element_name, "configuration") == 0) {
2487                 app_config->configuration_count--;
2488         } else if (strcmp (element_name, "startup") == 0) {
2489                 app_config->startup_count--;
2490         }
2491 }
2492
2493 static const GMarkupParser 
2494 mono_parser = {
2495         start_element,
2496         end_element,
2497         NULL,
2498         NULL,
2499         NULL
2500 };
2501
2502 static AppConfigInfo *
2503 app_config_parse (const char *exe_filename)
2504 {
2505         AppConfigInfo *app_config;
2506         GMarkupParseContext *context;
2507         char *text;
2508         gsize len;
2509         const char *bundled_config;
2510         char *config_filename;
2511
2512         bundled_config = mono_config_string_for_assembly_file (exe_filename);
2513
2514         if (bundled_config) {
2515                 text = g_strdup (bundled_config);
2516                 len = strlen (text);
2517         } else {
2518                 config_filename = g_strconcat (exe_filename, ".config", NULL);
2519
2520                 if (!g_file_get_contents (config_filename, &text, &len, NULL)) {
2521                         g_free (config_filename);
2522                         return NULL;
2523                 }
2524                 g_free (config_filename);
2525         }
2526
2527         app_config = g_new0 (AppConfigInfo, 1);
2528
2529         context = g_markup_parse_context_new (&mono_parser, 0, app_config, NULL);
2530         if (g_markup_parse_context_parse (context, text, len, NULL)) {
2531                 g_markup_parse_context_end_parse (context, NULL);
2532         }
2533         g_markup_parse_context_free (context);
2534         g_free (text);
2535         return app_config;
2536 }
2537
2538 static void 
2539 app_config_free (AppConfigInfo* app_config)
2540 {
2541         char *rt;
2542         GSList *list = app_config->supported_runtimes;
2543         while (list != NULL) {
2544                 rt = (char*)list->data;
2545                 g_free (rt);
2546                 list = g_slist_next (list);
2547         }
2548         g_slist_free (app_config->supported_runtimes);
2549         g_free (app_config->required_runtime);
2550         g_free (app_config);
2551 }
2552
2553
2554 static const MonoRuntimeInfo*
2555 get_runtime_by_version (const char *version)
2556 {
2557         int n;
2558         int max = G_N_ELEMENTS (supported_runtimes);
2559         int vlen;
2560
2561         if (!version)
2562                 return NULL;
2563
2564         for (n=0; n<max; n++) {
2565                 if (strcmp (version, supported_runtimes[n].runtime_version) == 0)
2566                         return &supported_runtimes[n];
2567         }
2568         
2569         vlen = strlen (version);
2570         if (vlen >= 4 && version [1] - '0' >= 4) {
2571                 for (n=0; n<max; n++) {
2572                         if (strncmp (version, supported_runtimes[n].runtime_version, 4) == 0)
2573                                 return &supported_runtimes[n];
2574                 }
2575         }
2576         
2577         return NULL;
2578 }
2579
2580 static void
2581 get_runtimes_from_exe (const char *exe_file, MonoImage **exe_image, const MonoRuntimeInfo** runtimes)
2582 {
2583         AppConfigInfo* app_config;
2584         char *version;
2585         const MonoRuntimeInfo* runtime = NULL;
2586         MonoImage *image = NULL;
2587         
2588         app_config = app_config_parse (exe_file);
2589         
2590         if (app_config != NULL) {
2591                 /* Check supportedRuntime elements, if none is supported, fail.
2592                  * If there are no such elements, look for a requiredRuntime element.
2593                  */
2594                 if (app_config->supported_runtimes != NULL) {
2595                         int n = 0;
2596                         GSList *list = app_config->supported_runtimes;
2597                         while (list != NULL) {
2598                                 version = (char*) list->data;
2599                                 runtime = get_runtime_by_version (version);
2600                                 if (runtime != NULL)
2601                                         runtimes [n++] = runtime;
2602                                 list = g_slist_next (list);
2603                         }
2604                         runtimes [n] = NULL;
2605                         app_config_free (app_config);
2606                         return;
2607                 }
2608                 
2609                 /* Check the requiredRuntime element. This is for 1.0 apps only. */
2610                 if (app_config->required_runtime != NULL) {
2611                         runtimes [0] = get_runtime_by_version (app_config->required_runtime);
2612                         runtimes [1] = NULL;
2613                         app_config_free (app_config);
2614                         return;
2615                 }
2616                 app_config_free (app_config);
2617         }
2618         
2619         /* Look for a runtime with the exact version */
2620         image = mono_assembly_open_from_bundle (exe_file, NULL, FALSE);
2621
2622         if (image == NULL)
2623                 image = mono_image_open (exe_file, NULL);
2624
2625         if (image == NULL) {
2626                 /* The image is wrong or the file was not found. In this case return
2627                  * a default runtime and leave to the initialization method the work of
2628                  * reporting the error.
2629                  */
2630                 runtimes [0] = get_runtime_by_version (DEFAULT_RUNTIME_VERSION);
2631                 runtimes [1] = NULL;
2632                 return;
2633         }
2634
2635         *exe_image = image;
2636
2637         runtimes [0] = get_runtime_by_version (image->version);
2638         runtimes [1] = NULL;
2639 }
2640
2641
2642 /**
2643  * mono_get_runtime_info:
2644  *
2645  * Returns: the version of the current runtime instance.
2646  */
2647 const MonoRuntimeInfo*
2648 mono_get_runtime_info (void)
2649 {
2650         return current_runtime;
2651 }
2652
2653 gchar *
2654 mono_debugger_check_runtime_version (const char *filename)
2655 {
2656         const MonoRuntimeInfo* runtimes [G_N_ELEMENTS (supported_runtimes) + 1];
2657         const MonoRuntimeInfo *rinfo;
2658         MonoImage *image;
2659
2660         get_runtimes_from_exe (filename, &image, runtimes);
2661         rinfo = runtimes [0];
2662
2663         if (!rinfo)
2664                 return g_strdup_printf ("Cannot get runtime version from assembly `%s'", filename);
2665
2666         if (rinfo != current_runtime)
2667                 return g_strdup_printf ("The Mono Debugger is currently using the `%s' runtime, but "
2668                                         "the assembly `%s' requires version `%s'", current_runtime->runtime_version,
2669                                         filename, rinfo->runtime_version);
2670
2671         return NULL;
2672 }
2673
2674 /**
2675  * mono_framework_version:
2676  *
2677  * Return the major version of the framework curently executing.
2678  */
2679 int
2680 mono_framework_version (void)
2681 {
2682         return current_runtime->framework_version [0] - '0';
2683 }
2684