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