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