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