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