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