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