Merge pull request #1150 from ludovic-henry/pr17c-delegate-trampoline
[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         g_assert (mono_root_domain);
860         mono_domain_lock (mono_root_domain);
861
862         /*
863          * We reuse MonoJitInfoTable to store AOT module info,
864          * this gives us async-safe lookup.
865          */
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_domain_unlock (mono_root_domain);
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 static int
989 try_block_hole_table_size (MonoJitInfo *ji)
990 {
991         MonoTryBlockHoleTableJitInfo *table;
992
993         table = mono_jit_info_get_try_block_hole_table_info (ji);
994         g_assert (table);
995         return sizeof (MonoTryBlockHoleTableJitInfo) + table->num_holes * sizeof (MonoTryBlockHoleJitInfo);
996 }
997
998 MonoArchEHJitInfo*
999 mono_jit_info_get_arch_eh_info (MonoJitInfo *ji)
1000 {
1001         if (ji->has_arch_eh_info) {
1002                 char *ptr = (char*)&ji->clauses [ji->num_clauses];
1003                 if (ji->has_generic_jit_info)
1004                         ptr += sizeof (MonoGenericJitInfo);
1005                 if (ji->has_try_block_holes)
1006                         ptr += try_block_hole_table_size (ji);
1007                 return (MonoArchEHJitInfo*)ptr;
1008         } else {
1009                 return NULL;
1010         }
1011 }
1012
1013 MonoMethodCasInfo*
1014 mono_jit_info_get_cas_info (MonoJitInfo *ji)
1015 {
1016         if (ji->has_cas_info) {
1017                 char *ptr = (char*)&ji->clauses [ji->num_clauses];
1018                 if (ji->has_generic_jit_info)
1019                         ptr += sizeof (MonoGenericJitInfo);
1020                 if (ji->has_try_block_holes)
1021                         ptr += try_block_hole_table_size (ji);
1022                 if (ji->has_arch_eh_info)
1023                         ptr += sizeof (MonoArchEHJitInfo);
1024                 return (MonoMethodCasInfo*)ptr;
1025         } else {
1026                 return NULL;
1027         }
1028 }
1029
1030 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
1031 #define ALIGN_PTR_TO(ptr,align) (gpointer)((((gssize)(ptr)) + (align - 1)) & (~(align - 1)))
1032
1033 static LockFreeMempool*
1034 lock_free_mempool_new (void)
1035 {
1036         return g_new0 (LockFreeMempool, 1);
1037 }
1038
1039 static void
1040 lock_free_mempool_free (LockFreeMempool *mp)
1041 {
1042         LockFreeMempoolChunk *chunk, *next;
1043
1044         chunk = mp->chunks;
1045         while (chunk) {
1046                 next = chunk->prev;
1047                 mono_vfree (chunk, mono_pagesize ());
1048                 chunk = next;
1049         }
1050         g_free (mp);
1051 }
1052
1053 /*
1054  * This is async safe
1055  */
1056 static LockFreeMempoolChunk*
1057 lock_free_mempool_chunk_new (LockFreeMempool *mp, int len)
1058 {
1059         LockFreeMempoolChunk *chunk, *prev;
1060         int size;
1061
1062         size = mono_pagesize ();
1063         while (size - sizeof (LockFreeMempoolChunk) < len)
1064                 size += mono_pagesize ();
1065         chunk = mono_valloc (0, size, MONO_MMAP_READ|MONO_MMAP_WRITE);
1066         g_assert (chunk);
1067         chunk->mem = ALIGN_PTR_TO ((char*)chunk + sizeof (LockFreeMempoolChunk), 16);
1068         chunk->size = ((char*)chunk + size) - (char*)chunk->mem;
1069         chunk->pos = 0;
1070
1071         /* Add to list of chunks lock-free */
1072         while (TRUE) {
1073                 prev = mp->chunks;
1074                 if (InterlockedCompareExchangePointer ((volatile gpointer*)&mp->chunks, chunk, prev) == prev)
1075                         break;
1076         }
1077         chunk->prev = prev;
1078
1079         return chunk;
1080 }
1081
1082 /*
1083  * This is async safe
1084  */
1085 static gpointer
1086 lock_free_mempool_alloc0 (LockFreeMempool *mp, guint size)
1087 {
1088         LockFreeMempoolChunk *chunk;
1089         gpointer res;
1090         int oldpos;
1091
1092         // FIXME: Free the allocator
1093
1094         size = ALIGN_TO (size, 8);
1095         chunk = mp->current;
1096         if (!chunk) {
1097                 chunk = lock_free_mempool_chunk_new (mp, size);
1098                 mono_memory_barrier ();
1099                 /* Publish */
1100                 mp->current = chunk;
1101         }
1102
1103         /* The code below is lock-free, 'chunk' is shared state */
1104         oldpos = InterlockedExchangeAdd (&chunk->pos, size);
1105         if (oldpos + size > chunk->size) {
1106                 chunk = lock_free_mempool_chunk_new (mp, size);
1107                 g_assert (chunk->pos + size <= chunk->size);
1108                 res = chunk->mem;
1109                 chunk->pos += size;
1110                 mono_memory_barrier ();
1111                 mp->current = chunk;
1112         } else {
1113                 res = (char*)chunk->mem + oldpos;
1114         }
1115
1116         return res;
1117 }
1118
1119 void
1120 mono_install_create_domain_hook (MonoCreateDomainFunc func)
1121 {
1122         create_domain_hook = func;
1123 }
1124
1125 void
1126 mono_install_free_domain_hook (MonoFreeDomainFunc func)
1127 {
1128         free_domain_hook = func;
1129 }
1130
1131 /**
1132  * mono_string_equal:
1133  * @s1: First string to compare
1134  * @s2: Second string to compare
1135  *
1136  * Returns FALSE if the strings differ.
1137  */
1138 gboolean
1139 mono_string_equal (MonoString *s1, MonoString *s2)
1140 {
1141         int l1 = mono_string_length (s1);
1142         int l2 = mono_string_length (s2);
1143
1144         if (s1 == s2)
1145                 return TRUE;
1146         if (l1 != l2)
1147                 return FALSE;
1148
1149         return memcmp (mono_string_chars (s1), mono_string_chars (s2), l1 * 2) == 0; 
1150 }
1151
1152 /**
1153  * mono_string_hash:
1154  * @s: the string to hash
1155  *
1156  * Returns the hash for the string.
1157  */
1158 guint
1159 mono_string_hash (MonoString *s)
1160 {
1161         const guint16 *p = mono_string_chars (s);
1162         int i, len = mono_string_length (s);
1163         guint h = 0;
1164
1165         for (i = 0; i < len; i++) {
1166                 h = (h << 5) - h + *p;
1167                 p++;
1168         }
1169
1170         return h;       
1171 }
1172
1173 static gboolean
1174 mono_ptrarray_equal (gpointer *s1, gpointer *s2)
1175 {
1176         int len = GPOINTER_TO_INT (s1 [0]);
1177         if (len != GPOINTER_TO_INT (s2 [0]))
1178                 return FALSE;
1179
1180         return memcmp (s1 + 1, s2 + 1, len * sizeof(gpointer)) == 0; 
1181 }
1182
1183 static guint
1184 mono_ptrarray_hash (gpointer *s)
1185 {
1186         int i;
1187         int len = GPOINTER_TO_INT (s [0]);
1188         guint hash = 0;
1189         
1190         for (i = 1; i < len; i++)
1191                 hash += GPOINTER_TO_UINT (s [i]);
1192
1193         return hash;    
1194 }
1195
1196 /*
1197  * Allocate an id for domain and set domain->domain_id.
1198  * LOCKING: must be called while holding appdomains_mutex.
1199  * We try to assign low numbers to the domain, so it can be used
1200  * as an index in data tables to lookup domain-specific info
1201  * with minimal memory overhead. We also try not to reuse the
1202  * same id too quickly (to help debugging).
1203  */
1204 static int
1205 domain_id_alloc (MonoDomain *domain)
1206 {
1207         int id = -1, i;
1208         if (!appdomains_list) {
1209                 appdomain_list_size = 2;
1210                 appdomains_list = mono_gc_alloc_fixed (appdomain_list_size * sizeof (void*), NULL);
1211         }
1212         for (i = appdomain_next; i < appdomain_list_size; ++i) {
1213                 if (!appdomains_list [i]) {
1214                         id = i;
1215                         break;
1216                 }
1217         }
1218         if (id == -1) {
1219                 for (i = 0; i < appdomain_next; ++i) {
1220                         if (!appdomains_list [i]) {
1221                                 id = i;
1222                                 break;
1223                         }
1224                 }
1225         }
1226         if (id == -1) {
1227                 MonoDomain **new_list;
1228                 int new_size = appdomain_list_size * 2;
1229                 if (new_size >= (1 << 16))
1230                         g_assert_not_reached ();
1231                 id = appdomain_list_size;
1232                 new_list = mono_gc_alloc_fixed (new_size * sizeof (void*), NULL);
1233                 memcpy (new_list, appdomains_list, appdomain_list_size * sizeof (void*));
1234                 mono_gc_free_fixed (appdomains_list);
1235                 appdomains_list = new_list;
1236                 appdomain_list_size = new_size;
1237         }
1238         domain->domain_id = id;
1239         appdomains_list [id] = domain;
1240         appdomain_next++;
1241         if (appdomain_next > appdomain_list_size)
1242                 appdomain_next = 0;
1243         return id;
1244 }
1245
1246 static gsize domain_gc_bitmap [sizeof(MonoDomain)/4/32 + 1];
1247 static gpointer domain_gc_desc = NULL;
1248 static guint32 domain_shadow_serial = 0L;
1249
1250 MonoDomain *
1251 mono_domain_create (void)
1252 {
1253         MonoDomain *domain;
1254         guint32 shadow_serial;
1255   
1256         mono_appdomains_lock ();
1257         shadow_serial = domain_shadow_serial++;
1258   
1259         if (!domain_gc_desc) {
1260                 unsigned int i, bit = 0;
1261                 for (i = G_STRUCT_OFFSET (MonoDomain, MONO_DOMAIN_FIRST_OBJECT); i < G_STRUCT_OFFSET (MonoDomain, MONO_DOMAIN_FIRST_GC_TRACKED); i += sizeof (gpointer)) {
1262                         bit = i / sizeof (gpointer);
1263                         domain_gc_bitmap [bit / 32] |= (gsize) 1 << (bit % 32);
1264                 }
1265                 domain_gc_desc = mono_gc_make_descr_from_bitmap ((gsize*)domain_gc_bitmap, bit + 1);
1266         }
1267         mono_appdomains_unlock ();
1268
1269 #ifdef HAVE_BOEHM_GC
1270         /*
1271          * Boehm doesn't like roots inside GC allocated objects, and alloc_fixed returns
1272          * a GC_MALLOC-ed object, contrary to the api docs. This causes random crashes when
1273          * running the corlib test suite.
1274          * To solve this, we pass a NULL descriptor, and don't register roots.
1275          */
1276         domain = mono_gc_alloc_fixed (sizeof (MonoDomain), NULL);
1277 #else
1278         domain = mono_gc_alloc_fixed (sizeof (MonoDomain), domain_gc_desc);
1279         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);
1280 #endif
1281         domain->shadow_serial = shadow_serial;
1282         domain->domain = NULL;
1283         domain->setup = NULL;
1284         domain->friendly_name = NULL;
1285         domain->search_path = NULL;
1286
1287         mono_profiler_appdomain_event (domain, MONO_PROFILE_START_LOAD);
1288
1289         domain->mp = mono_mempool_new ();
1290         domain->code_mp = mono_code_manager_new ();
1291         domain->lock_free_mp = lock_free_mempool_new ();
1292         domain->env = mono_g_hash_table_new_type ((GHashFunc)mono_string_hash, (GCompareFunc)mono_string_equal, MONO_HASH_KEY_VALUE_GC);
1293         domain->domain_assemblies = NULL;
1294         domain->assembly_bindings = NULL;
1295         domain->assembly_bindings_parsed = FALSE;
1296         domain->class_vtable_array = g_ptr_array_new ();
1297         domain->proxy_vtable_hash = g_hash_table_new ((GHashFunc)mono_ptrarray_hash, (GCompareFunc)mono_ptrarray_equal);
1298         domain->static_data_array = NULL;
1299         mono_jit_code_hash_init (&domain->jit_code_hash);
1300         domain->ldstr_table = mono_g_hash_table_new_type ((GHashFunc)mono_string_hash, (GCompareFunc)mono_string_equal, MONO_HASH_KEY_VALUE_GC);
1301         domain->num_jit_info_tables = 1;
1302         domain->jit_info_table = jit_info_table_new (domain);
1303         domain->jit_info_free_queue = NULL;
1304         domain->finalizable_objects_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1305         domain->ftnptrs_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1306
1307         InitializeCriticalSection (&domain->lock);
1308         InitializeCriticalSection (&domain->assemblies_lock);
1309         InitializeCriticalSection (&domain->jit_code_hash_lock);
1310         InitializeCriticalSection (&domain->finalizable_objects_hash_lock);
1311
1312         domain->method_rgctx_hash = NULL;
1313
1314         mono_appdomains_lock ();
1315         domain_id_alloc (domain);
1316         mono_appdomains_unlock ();
1317
1318 #ifndef DISABLE_PERFCOUNTERS
1319         mono_perfcounters->loader_appdomains++;
1320         mono_perfcounters->loader_total_appdomains++;
1321 #endif
1322
1323         mono_debug_domain_create (domain);
1324
1325         if (create_domain_hook)
1326                 create_domain_hook (domain);
1327
1328         mono_profiler_appdomain_loaded (domain, MONO_PROFILE_OK);
1329         
1330         return domain;
1331 }
1332
1333 /**
1334  * mono_init_internal:
1335  * 
1336  * Creates the initial application domain and initializes the mono_defaults
1337  * structure.
1338  * This function is guaranteed to not run any IL code.
1339  * If exe_filename is not NULL, the method will determine the required runtime
1340  * from the exe configuration file or the version PE field.
1341  * If runtime_version is not NULL, that runtime version will be used.
1342  * Either exe_filename or runtime_version must be provided.
1343  *
1344  * Returns: the initial domain.
1345  */
1346 static MonoDomain *
1347 mono_init_internal (const char *filename, const char *exe_filename, const char *runtime_version)
1348 {
1349         static MonoDomain *domain = NULL;
1350         MonoAssembly *ass = NULL;
1351         MonoImageOpenStatus status = MONO_IMAGE_OK;
1352         const MonoRuntimeInfo* runtimes [G_N_ELEMENTS (supported_runtimes) + 1];
1353         int n;
1354
1355 #ifdef DEBUG_DOMAIN_UNLOAD
1356         debug_domain_unload = TRUE;
1357 #endif
1358
1359         if (domain)
1360                 g_assert_not_reached ();
1361
1362 #ifdef HOST_WIN32
1363         /* Avoid system error message boxes. */
1364         SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
1365 #endif
1366
1367 #ifndef HOST_WIN32
1368         wapi_init ();
1369 #endif
1370
1371 #ifndef DISABLE_PERFCOUNTERS
1372         mono_perfcounters_init ();
1373 #endif
1374
1375         mono_counters_register ("Max native code in a domain", MONO_COUNTER_INT|MONO_COUNTER_JIT, &max_domain_code_size);
1376         mono_counters_register ("Max code space allocated in a domain", MONO_COUNTER_INT|MONO_COUNTER_JIT, &max_domain_code_alloc);
1377         mono_counters_register ("Total code space allocated", MONO_COUNTER_INT|MONO_COUNTER_JIT, &total_domain_code_alloc);
1378
1379         mono_gc_base_init ();
1380
1381         MONO_FAST_TLS_INIT (tls_appdomain);
1382         mono_native_tls_alloc (&appdomain_thread_id, NULL);
1383
1384         InitializeCriticalSection (&appdomains_mutex);
1385
1386         mono_metadata_init ();
1387         mono_images_init ();
1388         mono_assemblies_init ();
1389         mono_classes_init ();
1390         mono_loader_init ();
1391         mono_reflection_init ();
1392         mono_runtime_init_tls ();
1393
1394         /* FIXME: When should we release this memory? */
1395         MONO_GC_REGISTER_ROOT_FIXED (appdomains_list);
1396
1397         domain = mono_domain_create ();
1398         mono_root_domain = domain;
1399
1400         SET_APPDOMAIN (domain);
1401         
1402         /* Get a list of runtimes supported by the exe */
1403         if (exe_filename != NULL) {
1404                 /*
1405                  * This function will load the exe file as a MonoImage. We need to close it, but
1406                  * that would mean it would be reloaded later. So instead, we save it to
1407                  * exe_image, and close it during shutdown.
1408                  */
1409                 get_runtimes_from_exe (exe_filename, &exe_image, runtimes);
1410 #ifdef HOST_WIN32
1411                 if (!exe_image) {
1412                         exe_image = mono_assembly_open_from_bundle (exe_filename, NULL, FALSE);
1413                         if (!exe_image)
1414                                 exe_image = mono_image_open (exe_filename, NULL);
1415                 }
1416                 mono_fixup_exe_image (exe_image);
1417 #endif
1418         } else if (runtime_version != NULL) {
1419                 runtimes [0] = get_runtime_by_version (runtime_version);
1420                 runtimes [1] = NULL;
1421         }
1422
1423         if (runtimes [0] == NULL) {
1424                 const MonoRuntimeInfo *default_runtime = get_runtime_by_version (DEFAULT_RUNTIME_VERSION);
1425                 runtimes [0] = default_runtime;
1426                 runtimes [1] = NULL;
1427                 g_print ("WARNING: The runtime version supported by this application is unavailable.\n");
1428                 g_print ("Using default runtime: %s\n", default_runtime->runtime_version); 
1429         }
1430
1431         /* The selected runtime will be the first one for which there is a mscrolib.dll */
1432         for (n = 0; runtimes [n] != NULL && ass == NULL; n++) {
1433                 current_runtime = runtimes [n];
1434                 ass = mono_assembly_load_corlib (current_runtime, &status);
1435                 if (status != MONO_IMAGE_OK && status != MONO_IMAGE_ERROR_ERRNO)
1436                         break;
1437
1438         }
1439         
1440         if ((status != MONO_IMAGE_OK) || (ass == NULL)) {
1441                 switch (status){
1442                 case MONO_IMAGE_ERROR_ERRNO: {
1443                         char *corlib_file = g_build_filename (mono_assembly_getrootdir (), "mono", current_runtime->framework_version, "mscorlib.dll", NULL);
1444                         g_print ("The assembly mscorlib.dll was not found or could not be loaded.\n");
1445                         g_print ("It should have been installed in the `%s' directory.\n", corlib_file);
1446                         g_free (corlib_file);
1447                         break;
1448                 }
1449                 case MONO_IMAGE_IMAGE_INVALID:
1450                         g_print ("The file %s/mscorlib.dll is an invalid CIL image\n",
1451                                  mono_assembly_getrootdir ());
1452                         break;
1453                 case MONO_IMAGE_MISSING_ASSEMBLYREF:
1454                         g_print ("Missing assembly reference in %s/mscorlib.dll\n",
1455                                  mono_assembly_getrootdir ());
1456                         break;
1457                 case MONO_IMAGE_OK:
1458                         /* to suppress compiler warning */
1459                         break;
1460                 }
1461                 
1462                 exit (1);
1463         }
1464         mono_defaults.corlib = mono_assembly_get_image (ass);
1465
1466         mono_defaults.object_class = mono_class_from_name (
1467                 mono_defaults.corlib, "System", "Object");
1468         g_assert (mono_defaults.object_class != 0);
1469
1470         mono_defaults.void_class = mono_class_from_name (
1471                 mono_defaults.corlib, "System", "Void");
1472         g_assert (mono_defaults.void_class != 0);
1473
1474         mono_defaults.boolean_class = mono_class_from_name (
1475                 mono_defaults.corlib, "System", "Boolean");
1476         g_assert (mono_defaults.boolean_class != 0);
1477
1478         mono_defaults.byte_class = mono_class_from_name (
1479                 mono_defaults.corlib, "System", "Byte");
1480         g_assert (mono_defaults.byte_class != 0);
1481
1482         mono_defaults.sbyte_class = mono_class_from_name (
1483                 mono_defaults.corlib, "System", "SByte");
1484         g_assert (mono_defaults.sbyte_class != 0);
1485
1486         mono_defaults.int16_class = mono_class_from_name (
1487                 mono_defaults.corlib, "System", "Int16");
1488         g_assert (mono_defaults.int16_class != 0);
1489
1490         mono_defaults.uint16_class = mono_class_from_name (
1491                 mono_defaults.corlib, "System", "UInt16");
1492         g_assert (mono_defaults.uint16_class != 0);
1493
1494         mono_defaults.int32_class = mono_class_from_name (
1495                 mono_defaults.corlib, "System", "Int32");
1496         g_assert (mono_defaults.int32_class != 0);
1497
1498         mono_defaults.uint32_class = mono_class_from_name (
1499                 mono_defaults.corlib, "System", "UInt32");
1500         g_assert (mono_defaults.uint32_class != 0);
1501
1502         mono_defaults.uint_class = mono_class_from_name (
1503                 mono_defaults.corlib, "System", "UIntPtr");
1504         g_assert (mono_defaults.uint_class != 0);
1505
1506         mono_defaults.int_class = mono_class_from_name (
1507                 mono_defaults.corlib, "System", "IntPtr");
1508         g_assert (mono_defaults.int_class != 0);
1509
1510         mono_defaults.int64_class = mono_class_from_name (
1511                 mono_defaults.corlib, "System", "Int64");
1512         g_assert (mono_defaults.int64_class != 0);
1513
1514         mono_defaults.uint64_class = mono_class_from_name (
1515                 mono_defaults.corlib, "System", "UInt64");
1516         g_assert (mono_defaults.uint64_class != 0);
1517
1518         mono_defaults.single_class = mono_class_from_name (
1519                 mono_defaults.corlib, "System", "Single");
1520         g_assert (mono_defaults.single_class != 0);
1521
1522         mono_defaults.double_class = mono_class_from_name (
1523                 mono_defaults.corlib, "System", "Double");
1524         g_assert (mono_defaults.double_class != 0);
1525
1526         mono_defaults.char_class = mono_class_from_name (
1527                 mono_defaults.corlib, "System", "Char");
1528         g_assert (mono_defaults.char_class != 0);
1529
1530         mono_defaults.string_class = mono_class_from_name (
1531                 mono_defaults.corlib, "System", "String");
1532         g_assert (mono_defaults.string_class != 0);
1533
1534         mono_defaults.enum_class = mono_class_from_name (
1535                 mono_defaults.corlib, "System", "Enum");
1536         g_assert (mono_defaults.enum_class != 0);
1537
1538         mono_defaults.array_class = mono_class_from_name (
1539                 mono_defaults.corlib, "System", "Array");
1540         g_assert (mono_defaults.array_class != 0);
1541
1542         mono_defaults.delegate_class = mono_class_from_name (
1543                 mono_defaults.corlib, "System", "Delegate");
1544         g_assert (mono_defaults.delegate_class != 0 );
1545
1546         mono_defaults.multicastdelegate_class = mono_class_from_name (
1547                 mono_defaults.corlib, "System", "MulticastDelegate");
1548         g_assert (mono_defaults.multicastdelegate_class != 0 );
1549
1550         mono_defaults.asyncresult_class = mono_class_from_name (
1551                 mono_defaults.corlib, "System.Runtime.Remoting.Messaging", 
1552                 "AsyncResult");
1553         g_assert (mono_defaults.asyncresult_class != 0 );
1554
1555         mono_defaults.manualresetevent_class = mono_class_from_name (
1556                 mono_defaults.corlib, "System.Threading", "ManualResetEvent");
1557         g_assert (mono_defaults.manualresetevent_class != 0 );
1558
1559         mono_defaults.typehandle_class = mono_class_from_name (
1560                 mono_defaults.corlib, "System", "RuntimeTypeHandle");
1561         g_assert (mono_defaults.typehandle_class != 0);
1562
1563         mono_defaults.methodhandle_class = mono_class_from_name (
1564                 mono_defaults.corlib, "System", "RuntimeMethodHandle");
1565         g_assert (mono_defaults.methodhandle_class != 0);
1566
1567         mono_defaults.fieldhandle_class = mono_class_from_name (
1568                 mono_defaults.corlib, "System", "RuntimeFieldHandle");
1569         g_assert (mono_defaults.fieldhandle_class != 0);
1570
1571         mono_defaults.systemtype_class = mono_class_from_name (
1572                 mono_defaults.corlib, "System", "Type");
1573         g_assert (mono_defaults.systemtype_class != 0);
1574
1575         mono_defaults.monotype_class = mono_class_from_name (
1576                 mono_defaults.corlib, "System", "MonoType");
1577         g_assert (mono_defaults.monotype_class != 0);
1578
1579         mono_defaults.exception_class = mono_class_from_name (
1580                 mono_defaults.corlib, "System", "Exception");
1581         g_assert (mono_defaults.exception_class != 0);
1582
1583         mono_defaults.threadabortexception_class = mono_class_from_name (
1584                 mono_defaults.corlib, "System.Threading", "ThreadAbortException");
1585         g_assert (mono_defaults.threadabortexception_class != 0);
1586
1587         mono_defaults.thread_class = mono_class_from_name (
1588                 mono_defaults.corlib, "System.Threading", "Thread");
1589         g_assert (mono_defaults.thread_class != 0);
1590
1591         mono_defaults.internal_thread_class = mono_class_from_name (
1592                 mono_defaults.corlib, "System.Threading", "InternalThread");
1593         if (!mono_defaults.internal_thread_class) {
1594                 /* This can happen with an old mscorlib */
1595                 fprintf (stderr, "Corlib too old for this runtime.\n");
1596                 fprintf (stderr, "Loaded from: %s\n",
1597                                  mono_defaults.corlib? mono_image_get_filename (mono_defaults.corlib): "unknown");
1598                 exit (1);
1599         }
1600
1601         mono_defaults.appdomain_class = mono_class_from_name (
1602                 mono_defaults.corlib, "System", "AppDomain");
1603         g_assert (mono_defaults.appdomain_class != 0);
1604
1605 #ifndef DISABLE_REMOTING
1606         mono_defaults.transparent_proxy_class = mono_class_from_name (
1607                 mono_defaults.corlib, "System.Runtime.Remoting.Proxies", "TransparentProxy");
1608         g_assert (mono_defaults.transparent_proxy_class != 0);
1609
1610         mono_defaults.real_proxy_class = mono_class_from_name (
1611                 mono_defaults.corlib, "System.Runtime.Remoting.Proxies", "RealProxy");
1612         g_assert (mono_defaults.real_proxy_class != 0);
1613
1614         mono_defaults.marshalbyrefobject_class =  mono_class_from_name (
1615                 mono_defaults.corlib, "System", "MarshalByRefObject");
1616         g_assert (mono_defaults.marshalbyrefobject_class != 0);
1617
1618         mono_defaults.iremotingtypeinfo_class = mono_class_from_name (
1619                 mono_defaults.corlib, "System.Runtime.Remoting", "IRemotingTypeInfo");
1620         g_assert (mono_defaults.iremotingtypeinfo_class != 0);
1621 #endif
1622
1623         mono_defaults.mono_method_message_class = mono_class_from_name (
1624                 mono_defaults.corlib, "System.Runtime.Remoting.Messaging", "MonoMethodMessage");
1625         g_assert (mono_defaults.mono_method_message_class != 0);
1626
1627         mono_defaults.field_info_class = mono_class_from_name (
1628                 mono_defaults.corlib, "System.Reflection", "FieldInfo");
1629         g_assert (mono_defaults.field_info_class != 0);
1630
1631         mono_defaults.method_info_class = mono_class_from_name (
1632                 mono_defaults.corlib, "System.Reflection", "MethodInfo");
1633         g_assert (mono_defaults.method_info_class != 0);
1634
1635         mono_defaults.stringbuilder_class = mono_class_from_name (
1636                 mono_defaults.corlib, "System.Text", "StringBuilder");
1637         g_assert (mono_defaults.stringbuilder_class != 0);
1638
1639         mono_defaults.math_class = mono_class_from_name (
1640                 mono_defaults.corlib, "System", "Math");
1641         g_assert (mono_defaults.math_class != 0);
1642
1643         mono_defaults.stack_frame_class = mono_class_from_name (
1644                 mono_defaults.corlib, "System.Diagnostics", "StackFrame");
1645         g_assert (mono_defaults.stack_frame_class != 0);
1646
1647         mono_defaults.stack_trace_class = mono_class_from_name (
1648                 mono_defaults.corlib, "System.Diagnostics", "StackTrace");
1649         g_assert (mono_defaults.stack_trace_class != 0);
1650
1651         mono_defaults.marshal_class = mono_class_from_name (
1652                 mono_defaults.corlib, "System.Runtime.InteropServices", "Marshal");
1653         g_assert (mono_defaults.marshal_class != 0);
1654
1655         mono_defaults.typed_reference_class =  mono_class_from_name (
1656                 mono_defaults.corlib, "System", "TypedReference");
1657         g_assert (mono_defaults.typed_reference_class != 0);
1658
1659         mono_defaults.argumenthandle_class =  mono_class_from_name (
1660                 mono_defaults.corlib, "System", "RuntimeArgumentHandle");
1661         g_assert (mono_defaults.argumenthandle_class != 0);
1662
1663         mono_defaults.monitor_class =  mono_class_from_name (
1664                 mono_defaults.corlib, "System.Threading", "Monitor");
1665         g_assert (mono_defaults.monitor_class != 0);
1666
1667         mono_defaults.runtimesecurityframe_class = mono_class_from_name (
1668                 mono_defaults.corlib, "System.Security", "RuntimeSecurityFrame");
1669
1670         mono_defaults.executioncontext_class = mono_class_from_name (
1671                 mono_defaults.corlib, "System.Threading", "ExecutionContext");
1672
1673         mono_defaults.internals_visible_class = mono_class_from_name (
1674                 mono_defaults.corlib, "System.Runtime.CompilerServices", "InternalsVisibleToAttribute");
1675
1676         mono_defaults.critical_finalizer_object = mono_class_from_name (
1677                 mono_defaults.corlib, "System.Runtime.ConstrainedExecution", "CriticalFinalizerObject");
1678
1679         /*
1680          * mscorlib needs a little help, only now it can load its friends list (after we have
1681          * loaded the InternalsVisibleToAttribute), load it now
1682          */
1683         mono_assembly_load_friends (ass);
1684         
1685         mono_defaults.safehandle_class = mono_class_from_name (
1686                 mono_defaults.corlib, "System.Runtime.InteropServices", "SafeHandle");
1687
1688         mono_defaults.handleref_class = mono_class_from_name (
1689                 mono_defaults.corlib, "System.Runtime.InteropServices", "HandleRef");
1690
1691         mono_defaults.attribute_class = mono_class_from_name (
1692                 mono_defaults.corlib, "System", "Attribute");
1693
1694         mono_defaults.customattribute_data_class = mono_class_from_name (
1695                 mono_defaults.corlib, "System.Reflection", "CustomAttributeData");
1696
1697         /* these are initialized lazily when COM features are used */
1698
1699         mono_class_init (mono_defaults.array_class);
1700         mono_defaults.generic_nullable_class = mono_class_from_name (
1701                 mono_defaults.corlib, "System", "Nullable`1");
1702         mono_defaults.generic_ilist_class = mono_class_from_name (
1703                 mono_defaults.corlib, "System.Collections.Generic", "IList`1");
1704         mono_defaults.generic_ireadonlylist_class = mono_class_from_name (
1705                 mono_defaults.corlib, "System.Collections.Generic", "IReadOnlyList`1");
1706
1707         domain->friendly_name = g_path_get_basename (filename);
1708
1709         _mono_debug_init_corlib (domain);
1710
1711         return domain;
1712 }
1713
1714 /**
1715  * mono_init:
1716  * 
1717  * Creates the initial application domain and initializes the mono_defaults
1718  * structure.
1719  * This function is guaranteed to not run any IL code.
1720  * The runtime is initialized using the default runtime version.
1721  *
1722  * Returns: the initial domain.
1723  */
1724 MonoDomain *
1725 mono_init (const char *domain_name)
1726 {
1727         return mono_init_internal (domain_name, NULL, DEFAULT_RUNTIME_VERSION);
1728 }
1729
1730 /**
1731  * mono_init_from_assembly:
1732  * @domain_name: name to give to the initial domain
1733  * @filename: filename to load on startup
1734  *
1735  * Used by the runtime, users should use mono_jit_init instead.
1736  *
1737  * Creates the initial application domain and initializes the mono_defaults
1738  * structure.
1739  * This function is guaranteed to not run any IL code.
1740  * The runtime is initialized using the runtime version required by the
1741  * provided executable. The version is determined by looking at the exe 
1742  * configuration file and the version PE field)
1743  *
1744  * Returns: the initial domain.
1745  */
1746 MonoDomain *
1747 mono_init_from_assembly (const char *domain_name, const char *filename)
1748 {
1749         return mono_init_internal (domain_name, filename, NULL);
1750 }
1751
1752 /**
1753  * mono_init_version:
1754  * 
1755  * Used by the runtime, users should use mono_jit_init instead.
1756  * 
1757  * Creates the initial application domain and initializes the mono_defaults
1758  * structure.
1759  *
1760  * This function is guaranteed to not run any IL code.
1761  * The runtime is initialized using the provided rutime version.
1762  *
1763  * Returns: the initial domain.
1764  */
1765 MonoDomain *
1766 mono_init_version (const char *domain_name, const char *version)
1767 {
1768         return mono_init_internal (domain_name, NULL, version);
1769 }
1770
1771 /**
1772  * mono_cleanup:
1773  *
1774  * Cleans up all metadata modules. 
1775  */
1776 void
1777 mono_cleanup (void)
1778 {
1779         mono_close_exe_image ();
1780
1781         mono_defaults.corlib = NULL;
1782
1783         mono_config_cleanup ();
1784         mono_loader_cleanup ();
1785         mono_classes_cleanup ();
1786         mono_assemblies_cleanup ();
1787         mono_images_cleanup ();
1788         mono_debug_cleanup ();
1789         mono_metadata_cleanup ();
1790
1791         mono_native_tls_free (appdomain_thread_id);
1792         DeleteCriticalSection (&appdomains_mutex);
1793
1794 #ifndef HOST_WIN32
1795         wapi_cleanup ();
1796 #endif
1797 }
1798
1799 void
1800 mono_close_exe_image (void)
1801 {
1802         if (exe_image)
1803                 mono_image_close (exe_image);
1804 }
1805
1806 /**
1807  * mono_get_root_domain:
1808  *
1809  * The root AppDomain is the initial domain created by the runtime when it is
1810  * initialized.  Programs execute on this AppDomain, but can create new ones
1811  * later.   Currently there is no unmanaged API to create new AppDomains, this
1812  * must be done from managed code.
1813  *
1814  * Returns: the root appdomain, to obtain the current domain, use mono_domain_get ()
1815  */
1816 MonoDomain*
1817 mono_get_root_domain (void)
1818 {
1819         return mono_root_domain;
1820 }
1821
1822 /**
1823  * mono_domain_get:
1824  *
1825  * Returns: the current domain, to obtain the root domain use
1826  * mono_get_root_domain().
1827  */
1828 MonoDomain *
1829 mono_domain_get ()
1830 {
1831         return GET_APPDOMAIN ();
1832 }
1833
1834 void
1835 mono_domain_unset (void)
1836 {
1837         SET_APPDOMAIN (NULL);
1838 }
1839
1840 void
1841 mono_domain_set_internal_with_options (MonoDomain *domain, gboolean migrate_exception)
1842 {
1843         MonoInternalThread *thread;
1844
1845         if (mono_domain_get () == domain)
1846                 return;
1847
1848         SET_APPDOMAIN (domain);
1849         SET_APPCONTEXT (domain->default_context);
1850
1851         if (migrate_exception) {
1852                 thread = mono_thread_internal_current ();
1853                 if (!thread->abort_exc)
1854                         return;
1855
1856                 g_assert (thread->abort_exc->object.vtable->domain != domain);
1857                 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
1858                 g_assert (thread->abort_exc->object.vtable->domain == domain);
1859         }
1860 }
1861
1862 /**
1863  * mono_domain_set_internal:
1864  * @domain: the new domain
1865  *
1866  * Sets the current domain to @domain.
1867  */
1868 void
1869 mono_domain_set_internal (MonoDomain *domain)
1870 {
1871         mono_domain_set_internal_with_options (domain, TRUE);
1872 }
1873
1874 void
1875 mono_domain_foreach (MonoDomainFunc func, gpointer user_data)
1876 {
1877         int i, size;
1878         MonoDomain **copy;
1879
1880         /*
1881          * Create a copy of the data to avoid calling the user callback
1882          * inside the lock because that could lead to deadlocks.
1883          * We can do this because this function is not perf. critical.
1884          */
1885         mono_appdomains_lock ();
1886         size = appdomain_list_size;
1887         copy = mono_gc_alloc_fixed (appdomain_list_size * sizeof (void*), NULL);
1888         memcpy (copy, appdomains_list, appdomain_list_size * sizeof (void*));
1889         mono_appdomains_unlock ();
1890
1891         for (i = 0; i < size; ++i) {
1892                 if (copy [i])
1893                         func (copy [i], user_data);
1894         }
1895
1896         mono_gc_free_fixed (copy);
1897 }
1898
1899 /**
1900  * mono_domain_assembly_open:
1901  * @domain: the application domain
1902  * @name: file name of the assembly
1903  *
1904  * fixme: maybe we should integrate this with mono_assembly_open ??
1905  */
1906 MonoAssembly *
1907 mono_domain_assembly_open (MonoDomain *domain, const char *name)
1908 {
1909         MonoDomain *current;
1910         MonoAssembly *ass;
1911         GSList *tmp;
1912
1913         mono_domain_assemblies_lock (domain);
1914         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1915                 ass = tmp->data;
1916                 if (strcmp (name, ass->aname.name) == 0) {
1917                         mono_domain_assemblies_unlock (domain);
1918                         return ass;
1919                 }
1920         }
1921         mono_domain_assemblies_unlock (domain);
1922
1923         if (domain != mono_domain_get ()) {
1924                 current = mono_domain_get ();
1925
1926                 mono_domain_set (domain, FALSE);
1927                 ass = mono_assembly_open (name, NULL);
1928                 mono_domain_set (current, FALSE);
1929         } else {
1930                 ass = mono_assembly_open (name, NULL);
1931         }
1932
1933         return ass;
1934 }
1935
1936 static void
1937 unregister_vtable_reflection_type (MonoVTable *vtable)
1938 {
1939         MonoObject *type = vtable->type;
1940
1941         if (type->vtable->klass != mono_defaults.monotype_class)
1942                 MONO_GC_UNREGISTER_ROOT_IF_MOVING (vtable->type);
1943 }
1944
1945 void
1946 mono_domain_free (MonoDomain *domain, gboolean force)
1947 {
1948         int code_size, code_alloc;
1949         GSList *tmp;
1950         gpointer *p;
1951
1952         if ((domain == mono_root_domain) && !force) {
1953                 g_warning ("cant unload root domain");
1954                 return;
1955         }
1956
1957         if (mono_dont_free_domains)
1958                 return;
1959
1960         mono_profiler_appdomain_event (domain, MONO_PROFILE_START_UNLOAD);
1961
1962         mono_debug_domain_unload (domain);
1963
1964         mono_appdomains_lock ();
1965         appdomains_list [domain->domain_id] = NULL;
1966         mono_appdomains_unlock ();
1967
1968         /* must do this early as it accesses fields and types */
1969         if (domain->special_static_fields) {
1970                 mono_alloc_special_static_data_free (domain->special_static_fields);
1971                 g_hash_table_destroy (domain->special_static_fields);
1972                 domain->special_static_fields = NULL;
1973         }
1974
1975         /*
1976          * We must destroy all these hash tables here because they
1977          * contain references to managed objects belonging to the
1978          * domain.  Once we let the GC clear the domain there must be
1979          * no more such references, or we'll crash if a collection
1980          * occurs.
1981          */
1982         mono_g_hash_table_destroy (domain->ldstr_table);
1983         domain->ldstr_table = NULL;
1984
1985         mono_g_hash_table_destroy (domain->env);
1986         domain->env = NULL;
1987
1988         if (domain->tlsrec_list) {
1989                 mono_thread_destroy_domain_tls (domain);
1990                 domain->tlsrec_list = NULL;
1991         }
1992
1993         mono_reflection_cleanup_domain (domain);
1994
1995         /* This must be done before type_hash is freed */
1996         if (domain->class_vtable_array) {
1997                 int i;
1998                 for (i = 0; i < domain->class_vtable_array->len; ++i)
1999                         unregister_vtable_reflection_type (g_ptr_array_index (domain->class_vtable_array, i));
2000         }
2001
2002         if (domain->type_hash) {
2003                 mono_g_hash_table_destroy (domain->type_hash);
2004                 domain->type_hash = NULL;
2005         }
2006         if (domain->type_init_exception_hash) {
2007                 mono_g_hash_table_destroy (domain->type_init_exception_hash);
2008                 domain->type_init_exception_hash = NULL;
2009         }
2010
2011         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
2012                 MonoAssembly *ass = tmp->data;
2013                 mono_assembly_release_gc_roots (ass);
2014         }
2015
2016         /* Have to zero out reference fields since they will be invalidated by the clear_domain () call below */
2017         for (p = (gpointer*)&domain->MONO_DOMAIN_FIRST_OBJECT; p < (gpointer*)&domain->MONO_DOMAIN_FIRST_GC_TRACKED; ++p)
2018                 *p = NULL;
2019
2020         /* This needs to be done before closing assemblies */
2021         mono_gc_clear_domain (domain);
2022
2023         /* Close dynamic assemblies first, since they have no ref count */
2024         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
2025                 MonoAssembly *ass = tmp->data;
2026                 if (!ass->image || !ass->image->dynamic)
2027                         continue;
2028                 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);
2029                 if (!mono_assembly_close_except_image_pools (ass))
2030                         tmp->data = NULL;
2031         }
2032
2033         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
2034                 MonoAssembly *ass = tmp->data;
2035                 if (!ass)
2036                         continue;
2037                 if (!ass->image || ass->image->dynamic)
2038                         continue;
2039                 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);
2040                 if (!mono_assembly_close_except_image_pools (ass))
2041                         tmp->data = NULL;
2042         }
2043
2044         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
2045                 MonoAssembly *ass = tmp->data;
2046                 if (ass)
2047                         mono_assembly_close_finish (ass);
2048         }
2049         g_slist_free (domain->domain_assemblies);
2050         domain->domain_assemblies = NULL;
2051
2052         /* 
2053          * Send this after the assemblies have been unloaded and the domain is still in a 
2054          * usable state.
2055          */
2056         mono_profiler_appdomain_event (domain, MONO_PROFILE_END_UNLOAD);
2057
2058         if (free_domain_hook)
2059                 free_domain_hook (domain);
2060
2061         /* FIXME: free delegate_hash_table when it's used */
2062         if (domain->search_path) {
2063                 g_strfreev (domain->search_path);
2064                 domain->search_path = NULL;
2065         }
2066         domain->create_proxy_for_type_method = NULL;
2067         domain->private_invoke_method = NULL;
2068         domain->default_context = NULL;
2069         domain->out_of_memory_ex = NULL;
2070         domain->null_reference_ex = NULL;
2071         domain->stack_overflow_ex = NULL;
2072         domain->ephemeron_tombstone = NULL;
2073         domain->entry_assembly = NULL;
2074
2075         g_free (domain->friendly_name);
2076         domain->friendly_name = NULL;
2077         g_ptr_array_free (domain->class_vtable_array, TRUE);
2078         domain->class_vtable_array = NULL;
2079         g_hash_table_destroy (domain->proxy_vtable_hash);
2080         domain->proxy_vtable_hash = NULL;
2081         if (domain->static_data_array) {
2082                 mono_gc_free_fixed (domain->static_data_array);
2083                 domain->static_data_array = NULL;
2084         }
2085         mono_internal_hash_table_destroy (&domain->jit_code_hash);
2086
2087         /*
2088          * There might still be jit info tables of this domain which
2089          * are not freed.  Since the domain cannot be in use anymore,
2090          * this will free them.
2091          */
2092         mono_thread_hazardous_try_free_all ();
2093         if (domain->aot_modules)
2094                 jit_info_table_free (domain->aot_modules);
2095         g_assert (domain->num_jit_info_tables == 1);
2096         jit_info_table_free (domain->jit_info_table);
2097         domain->jit_info_table = NULL;
2098         g_assert (!domain->jit_info_free_queue);
2099
2100         /* collect statistics */
2101         code_alloc = mono_code_manager_size (domain->code_mp, &code_size);
2102         total_domain_code_alloc += code_alloc;
2103         max_domain_code_alloc = MAX (max_domain_code_alloc, code_alloc);
2104         max_domain_code_size = MAX (max_domain_code_size, code_size);
2105
2106         if (debug_domain_unload) {
2107                 mono_mempool_invalidate (domain->mp);
2108                 mono_code_manager_invalidate (domain->code_mp);
2109         } else {
2110 #ifndef DISABLE_PERFCOUNTERS
2111                 mono_perfcounters->loader_bytes -= mono_mempool_get_allocated (domain->mp);
2112 #endif
2113                 mono_mempool_destroy (domain->mp);
2114                 domain->mp = NULL;
2115                 mono_code_manager_destroy (domain->code_mp);
2116                 domain->code_mp = NULL;
2117         }
2118         lock_free_mempool_free (domain->lock_free_mp);
2119         domain->lock_free_mp = NULL;
2120
2121         g_hash_table_destroy (domain->finalizable_objects_hash);
2122         domain->finalizable_objects_hash = NULL;
2123         if (domain->method_rgctx_hash) {
2124                 g_hash_table_destroy (domain->method_rgctx_hash);
2125                 domain->method_rgctx_hash = NULL;
2126         }
2127         if (domain->generic_virtual_cases) {
2128                 g_hash_table_destroy (domain->generic_virtual_cases);
2129                 domain->generic_virtual_cases = NULL;
2130         }
2131         if (domain->generic_virtual_thunks) {
2132                 g_hash_table_destroy (domain->generic_virtual_thunks);
2133                 domain->generic_virtual_thunks = NULL;
2134         }
2135         if (domain->ftnptrs_hash) {
2136                 g_hash_table_destroy (domain->ftnptrs_hash);
2137                 domain->ftnptrs_hash = NULL;
2138         }
2139
2140         DeleteCriticalSection (&domain->finalizable_objects_hash_lock);
2141         DeleteCriticalSection (&domain->assemblies_lock);
2142         DeleteCriticalSection (&domain->jit_code_hash_lock);
2143         DeleteCriticalSection (&domain->lock);
2144         domain->setup = NULL;
2145
2146         mono_gc_deregister_root ((char*)&(domain->MONO_DOMAIN_FIRST_GC_TRACKED));
2147
2148         /* FIXME: anything else required ? */
2149
2150         mono_gc_free_fixed (domain);
2151
2152 #ifndef DISABLE_PERFCOUNTERS
2153         mono_perfcounters->loader_appdomains--;
2154 #endif
2155
2156         if (domain == mono_root_domain)
2157                 mono_root_domain = NULL;
2158 }
2159
2160 /**
2161  * mono_domain_get_id:
2162  * @domainid: the ID
2163  *
2164  * Returns: the a domain for a specific domain id.
2165  */
2166 MonoDomain * 
2167 mono_domain_get_by_id (gint32 domainid) 
2168 {
2169         MonoDomain * domain;
2170
2171         mono_appdomains_lock ();
2172         if (domainid < appdomain_list_size)
2173                 domain = appdomains_list [domainid];
2174         else
2175                 domain = NULL;
2176         mono_appdomains_unlock ();
2177
2178         return domain;
2179 }
2180
2181 gint32
2182 mono_domain_get_id (MonoDomain *domain)
2183 {
2184         return domain->domain_id;
2185 }
2186
2187 /*
2188  * mono_domain_alloc:
2189  *
2190  * LOCKING: Acquires the domain lock.
2191  */
2192 gpointer
2193 mono_domain_alloc (MonoDomain *domain, guint size)
2194 {
2195         gpointer res;
2196
2197         mono_domain_lock (domain);
2198 #ifndef DISABLE_PERFCOUNTERS
2199         mono_perfcounters->loader_bytes += size;
2200 #endif
2201         res = mono_mempool_alloc (domain->mp, size);
2202         mono_domain_unlock (domain);
2203
2204         return res;
2205 }
2206
2207 /*
2208  * mono_domain_alloc0:
2209  *
2210  * LOCKING: Acquires the domain lock.
2211  */
2212 gpointer
2213 mono_domain_alloc0 (MonoDomain *domain, guint size)
2214 {
2215         gpointer res;
2216
2217         mono_domain_lock (domain);
2218 #ifndef DISABLE_PERFCOUNTERS
2219         mono_perfcounters->loader_bytes += size;
2220 #endif
2221         res = mono_mempool_alloc0 (domain->mp, size);
2222         mono_domain_unlock (domain);
2223
2224         return res;
2225 }
2226
2227 gpointer
2228 mono_domain_alloc0_lock_free (MonoDomain *domain, guint size)
2229 {
2230         return lock_free_mempool_alloc0 (domain->lock_free_mp, size);
2231 }
2232
2233 /*
2234  * mono_domain_code_reserve:
2235  *
2236  * LOCKING: Acquires the domain lock.
2237  */
2238 void*
2239 mono_domain_code_reserve (MonoDomain *domain, int size)
2240 {
2241         gpointer res;
2242
2243         mono_domain_lock (domain);
2244         res = mono_code_manager_reserve (domain->code_mp, size);
2245         mono_domain_unlock (domain);
2246
2247         return res;
2248 }
2249
2250 /*
2251  * mono_domain_code_reserve_align:
2252  *
2253  * LOCKING: Acquires the domain lock.
2254  */
2255 void*
2256 mono_domain_code_reserve_align (MonoDomain *domain, int size, int alignment)
2257 {
2258         gpointer res;
2259
2260         mono_domain_lock (domain);
2261         res = mono_code_manager_reserve_align (domain->code_mp, size, alignment);
2262         mono_domain_unlock (domain);
2263
2264         return res;
2265 }
2266
2267 /*
2268  * mono_domain_code_commit:
2269  *
2270  * LOCKING: Acquires the domain lock.
2271  */
2272 void
2273 mono_domain_code_commit (MonoDomain *domain, void *data, int size, int newsize)
2274 {
2275         mono_domain_lock (domain);
2276         mono_code_manager_commit (domain->code_mp, data, size, newsize);
2277         mono_domain_unlock (domain);
2278 }
2279
2280 #if defined(__native_client_codegen__) && defined(__native_client__)
2281 /*
2282  * Given the temporary buffer (allocated by mono_domain_code_reserve) into which
2283  * we are generating code, return a pointer to the destination in the dynamic 
2284  * code segment into which the code will be copied when mono_domain_code_commit
2285  * is called.
2286  * LOCKING: Acquires the domain lock.
2287  */
2288 void *
2289 nacl_domain_get_code_dest (MonoDomain *domain, void *data)
2290 {
2291         void *dest;
2292         mono_domain_lock (domain);
2293         dest = nacl_code_manager_get_code_dest (domain->code_mp, data);
2294         mono_domain_unlock (domain);
2295         return dest;
2296 }
2297
2298 /* 
2299  * Convenience function which calls mono_domain_code_commit to validate and copy
2300  * the code. The caller sets *buf_base and *buf_size to the start and size of
2301  * the buffer (allocated by mono_domain_code_reserve), and *code_end to the byte
2302  * after the last instruction byte. On return, *buf_base will point to the start
2303  * of the copied in the code segment, and *code_end will point after the end of 
2304  * the copied code.
2305  */
2306 void
2307 nacl_domain_code_validate (MonoDomain *domain, guint8 **buf_base, int buf_size, guint8 **code_end)
2308 {
2309         guint8 *tmp = nacl_domain_get_code_dest (domain, *buf_base);
2310         mono_domain_code_commit (domain, *buf_base, buf_size, *code_end - *buf_base);
2311         *code_end = tmp + (*code_end - *buf_base);
2312         *buf_base = tmp;
2313 }
2314
2315 #else
2316
2317 /* no-op versions of Native Client functions */
2318
2319 void *
2320 nacl_domain_get_code_dest (MonoDomain *domain, void *data)
2321 {
2322         return data;
2323 }
2324
2325 void
2326 nacl_domain_code_validate (MonoDomain *domain, guint8 **buf_base, int buf_size, guint8 **code_end)
2327 {
2328 }
2329
2330 #endif
2331
2332 /*
2333  * mono_domain_code_foreach:
2334  * Iterate over the code thunks of the code manager of @domain.
2335  * 
2336  * The @func callback MUST not take any locks. If it really needs to, it must respect
2337  * the locking rules of the runtime: http://www.mono-project.com/Mono:Runtime:Documentation:ThreadSafety 
2338  * LOCKING: Acquires the domain lock.
2339  */
2340
2341 void
2342 mono_domain_code_foreach (MonoDomain *domain, MonoCodeManagerFunc func, void *user_data)
2343 {
2344         mono_domain_lock (domain);
2345         mono_code_manager_foreach (domain->code_mp, func, user_data);
2346         mono_domain_unlock (domain);
2347 }
2348
2349
2350 void 
2351 mono_context_set (MonoAppContext * new_context)
2352 {
2353         SET_APPCONTEXT (new_context);
2354 }
2355
2356 MonoAppContext * 
2357 mono_context_get (void)
2358 {
2359         return GET_APPCONTEXT ();
2360 }
2361
2362 /* LOCKING: the caller holds the lock for this domain */
2363 void
2364 mono_domain_add_class_static_data (MonoDomain *domain, MonoClass *klass, gpointer data, guint32 *bitmap)
2365 {
2366         /* The first entry in the array is the index of the next free slot
2367          * and the total size of the array
2368          */
2369         int next;
2370         if (domain->static_data_array) {
2371                 int size = GPOINTER_TO_INT (domain->static_data_array [1]);
2372                 next = GPOINTER_TO_INT (domain->static_data_array [0]);
2373                 if (next >= size) {
2374                         /* 'data' is allocated by alloc_fixed */
2375                         gpointer *new_array = mono_gc_alloc_fixed (sizeof (gpointer) * (size * 2), MONO_GC_ROOT_DESCR_FOR_FIXED (size * 2));
2376                         mono_gc_memmove_aligned (new_array, domain->static_data_array, sizeof (gpointer) * size);
2377                         size *= 2;
2378                         new_array [1] = GINT_TO_POINTER (size);
2379                         mono_gc_free_fixed (domain->static_data_array);
2380                         domain->static_data_array = new_array;
2381                 }
2382         } else {
2383                 int size = 32;
2384                 gpointer *new_array = mono_gc_alloc_fixed (sizeof (gpointer) * size, MONO_GC_ROOT_DESCR_FOR_FIXED (size));
2385                 next = 2;
2386                 new_array [0] = GINT_TO_POINTER (next);
2387                 new_array [1] = GINT_TO_POINTER (size);
2388                 domain->static_data_array = new_array;
2389         }
2390         domain->static_data_array [next++] = data;
2391         domain->static_data_array [0] = GINT_TO_POINTER (next);
2392 }
2393
2394 MonoImage*
2395 mono_get_corlib (void)
2396 {
2397         return mono_defaults.corlib;
2398 }
2399
2400 MonoClass*
2401 mono_get_object_class (void)
2402 {
2403         return mono_defaults.object_class;
2404 }
2405
2406 MonoClass*
2407 mono_get_byte_class (void)
2408 {
2409         return mono_defaults.byte_class;
2410 }
2411
2412 MonoClass*
2413 mono_get_void_class (void)
2414 {
2415         return mono_defaults.void_class;
2416 }
2417
2418 MonoClass*
2419 mono_get_boolean_class (void)
2420 {
2421         return mono_defaults.boolean_class;
2422 }
2423
2424 MonoClass*
2425 mono_get_sbyte_class (void)
2426 {
2427         return mono_defaults.sbyte_class;
2428 }
2429
2430 MonoClass*
2431 mono_get_int16_class (void)
2432 {
2433         return mono_defaults.int16_class;
2434 }
2435
2436 MonoClass*
2437 mono_get_uint16_class (void)
2438 {
2439         return mono_defaults.uint16_class;
2440 }
2441
2442 MonoClass*
2443 mono_get_int32_class (void)
2444 {
2445         return mono_defaults.int32_class;
2446 }
2447
2448 MonoClass*
2449 mono_get_uint32_class (void)
2450 {
2451         return mono_defaults.uint32_class;
2452 }
2453
2454 MonoClass*
2455 mono_get_intptr_class (void)
2456 {
2457         return mono_defaults.int_class;
2458 }
2459
2460 MonoClass*
2461 mono_get_uintptr_class (void)
2462 {
2463         return mono_defaults.uint_class;
2464 }
2465
2466 MonoClass*
2467 mono_get_int64_class (void)
2468 {
2469         return mono_defaults.int64_class;
2470 }
2471
2472 MonoClass*
2473 mono_get_uint64_class (void)
2474 {
2475         return mono_defaults.uint64_class;
2476 }
2477
2478 MonoClass*
2479 mono_get_single_class (void)
2480 {
2481         return mono_defaults.single_class;
2482 }
2483
2484 MonoClass*
2485 mono_get_double_class (void)
2486 {
2487         return mono_defaults.double_class;
2488 }
2489
2490 MonoClass*
2491 mono_get_char_class (void)
2492 {
2493         return mono_defaults.char_class;
2494 }
2495
2496 MonoClass*
2497 mono_get_string_class (void)
2498 {
2499         return mono_defaults.string_class;
2500 }
2501
2502 MonoClass*
2503 mono_get_enum_class (void)
2504 {
2505         return mono_defaults.enum_class;
2506 }
2507
2508 MonoClass*
2509 mono_get_array_class (void)
2510 {
2511         return mono_defaults.array_class;
2512 }
2513
2514 MonoClass*
2515 mono_get_thread_class (void)
2516 {
2517         return mono_defaults.thread_class;
2518 }
2519
2520 MonoClass*
2521 mono_get_exception_class (void)
2522 {
2523         return mono_defaults.exception_class;
2524 }
2525
2526
2527 static char* get_attribute_value (const gchar **attribute_names, 
2528                                         const gchar **attribute_values, 
2529                                         const char *att_name)
2530 {
2531         int n;
2532         for (n=0; attribute_names[n] != NULL; n++) {
2533                 if (strcmp (attribute_names[n], att_name) == 0)
2534                         return g_strdup (attribute_values[n]);
2535         }
2536         return NULL;
2537 }
2538
2539 static void start_element (GMarkupParseContext *context, 
2540                            const gchar         *element_name,
2541                            const gchar        **attribute_names,
2542                            const gchar        **attribute_values,
2543                            gpointer             user_data,
2544                            GError             **error)
2545 {
2546         AppConfigInfo* app_config = (AppConfigInfo*) user_data;
2547         
2548         if (strcmp (element_name, "configuration") == 0) {
2549                 app_config->configuration_count++;
2550                 return;
2551         }
2552         if (strcmp (element_name, "startup") == 0) {
2553                 app_config->startup_count++;
2554                 return;
2555         }
2556         
2557         if (app_config->configuration_count != 1 || app_config->startup_count != 1)
2558                 return;
2559         
2560         if (strcmp (element_name, "requiredRuntime") == 0) {
2561                 app_config->required_runtime = get_attribute_value (attribute_names, attribute_values, "version");
2562         } else if (strcmp (element_name, "supportedRuntime") == 0) {
2563                 char *version = get_attribute_value (attribute_names, attribute_values, "version");
2564                 app_config->supported_runtimes = g_slist_append (app_config->supported_runtimes, version);
2565         }
2566 }
2567
2568 static void end_element   (GMarkupParseContext *context,
2569                            const gchar         *element_name,
2570                            gpointer             user_data,
2571                            GError             **error)
2572 {
2573         AppConfigInfo* app_config = (AppConfigInfo*) user_data;
2574         
2575         if (strcmp (element_name, "configuration") == 0) {
2576                 app_config->configuration_count--;
2577         } else if (strcmp (element_name, "startup") == 0) {
2578                 app_config->startup_count--;
2579         }
2580 }
2581
2582 static const GMarkupParser 
2583 mono_parser = {
2584         start_element,
2585         end_element,
2586         NULL,
2587         NULL,
2588         NULL
2589 };
2590
2591 static AppConfigInfo *
2592 app_config_parse (const char *exe_filename)
2593 {
2594         AppConfigInfo *app_config;
2595         GMarkupParseContext *context;
2596         char *text;
2597         gsize len;
2598         const char *bundled_config;
2599         char *config_filename;
2600
2601         bundled_config = mono_config_string_for_assembly_file (exe_filename);
2602
2603         if (bundled_config) {
2604                 text = g_strdup (bundled_config);
2605                 len = strlen (text);
2606         } else {
2607                 config_filename = g_strconcat (exe_filename, ".config", NULL);
2608
2609                 if (!g_file_get_contents (config_filename, &text, &len, NULL)) {
2610                         g_free (config_filename);
2611                         return NULL;
2612                 }
2613                 g_free (config_filename);
2614         }
2615
2616         app_config = g_new0 (AppConfigInfo, 1);
2617
2618         context = g_markup_parse_context_new (&mono_parser, 0, app_config, NULL);
2619         if (g_markup_parse_context_parse (context, text, len, NULL)) {
2620                 g_markup_parse_context_end_parse (context, NULL);
2621         }
2622         g_markup_parse_context_free (context);
2623         g_free (text);
2624         return app_config;
2625 }
2626
2627 static void 
2628 app_config_free (AppConfigInfo* app_config)
2629 {
2630         char *rt;
2631         GSList *list = app_config->supported_runtimes;
2632         while (list != NULL) {
2633                 rt = (char*)list->data;
2634                 g_free (rt);
2635                 list = g_slist_next (list);
2636         }
2637         g_slist_free (app_config->supported_runtimes);
2638         g_free (app_config->required_runtime);
2639         g_free (app_config);
2640 }
2641
2642
2643 static const MonoRuntimeInfo*
2644 get_runtime_by_version (const char *version)
2645 {
2646         int n;
2647         int max = G_N_ELEMENTS (supported_runtimes);
2648         int vlen;
2649
2650         if (!version)
2651                 return NULL;
2652
2653         for (n=0; n<max; n++) {
2654                 if (strcmp (version, supported_runtimes[n].runtime_version) == 0)
2655                         return &supported_runtimes[n];
2656         }
2657         
2658         vlen = strlen (version);
2659         if (vlen >= 4 && version [1] - '0' >= 4) {
2660                 for (n=0; n<max; n++) {
2661                         if (strncmp (version, supported_runtimes[n].runtime_version, 4) == 0)
2662                                 return &supported_runtimes[n];
2663                 }
2664         }
2665         
2666         return NULL;
2667 }
2668
2669 static void
2670 get_runtimes_from_exe (const char *exe_file, MonoImage **exe_image, const MonoRuntimeInfo** runtimes)
2671 {
2672         AppConfigInfo* app_config;
2673         char *version;
2674         const MonoRuntimeInfo* runtime = NULL;
2675         MonoImage *image = NULL;
2676         
2677         app_config = app_config_parse (exe_file);
2678         
2679         if (app_config != NULL) {
2680                 /* Check supportedRuntime elements, if none is supported, fail.
2681                  * If there are no such elements, look for a requiredRuntime element.
2682                  */
2683                 if (app_config->supported_runtimes != NULL) {
2684                         int n = 0;
2685                         GSList *list = app_config->supported_runtimes;
2686                         while (list != NULL) {
2687                                 version = (char*) list->data;
2688                                 runtime = get_runtime_by_version (version);
2689                                 if (runtime != NULL)
2690                                         runtimes [n++] = runtime;
2691                                 list = g_slist_next (list);
2692                         }
2693                         runtimes [n] = NULL;
2694                         app_config_free (app_config);
2695                         return;
2696                 }
2697                 
2698                 /* Check the requiredRuntime element. This is for 1.0 apps only. */
2699                 if (app_config->required_runtime != NULL) {
2700                         runtimes [0] = get_runtime_by_version (app_config->required_runtime);
2701                         runtimes [1] = NULL;
2702                         app_config_free (app_config);
2703                         return;
2704                 }
2705                 app_config_free (app_config);
2706         }
2707         
2708         /* Look for a runtime with the exact version */
2709         image = mono_assembly_open_from_bundle (exe_file, NULL, FALSE);
2710
2711         if (image == NULL)
2712                 image = mono_image_open (exe_file, NULL);
2713
2714         if (image == NULL) {
2715                 /* The image is wrong or the file was not found. In this case return
2716                  * a default runtime and leave to the initialization method the work of
2717                  * reporting the error.
2718                  */
2719                 runtimes [0] = get_runtime_by_version (DEFAULT_RUNTIME_VERSION);
2720                 runtimes [1] = NULL;
2721                 return;
2722         }
2723
2724         *exe_image = image;
2725
2726         runtimes [0] = get_runtime_by_version (image->version);
2727         runtimes [1] = NULL;
2728 }
2729
2730
2731 /**
2732  * mono_get_runtime_info:
2733  *
2734  * Returns: the version of the current runtime instance.
2735  */
2736 const MonoRuntimeInfo*
2737 mono_get_runtime_info (void)
2738 {
2739         return current_runtime;
2740 }
2741
2742 gchar *
2743 mono_debugger_check_runtime_version (const char *filename)
2744 {
2745         const MonoRuntimeInfo* runtimes [G_N_ELEMENTS (supported_runtimes) + 1];
2746         const MonoRuntimeInfo *rinfo;
2747         MonoImage *image;
2748
2749         get_runtimes_from_exe (filename, &image, runtimes);
2750         rinfo = runtimes [0];
2751
2752         if (!rinfo)
2753                 return g_strdup_printf ("Cannot get runtime version from assembly `%s'", filename);
2754
2755         if (rinfo != current_runtime)
2756                 return g_strdup_printf ("The Mono Debugger is currently using the `%s' runtime, but "
2757                                         "the assembly `%s' requires version `%s'", current_runtime->runtime_version,
2758                                         filename, rinfo->runtime_version);
2759
2760         return NULL;
2761 }
2762
2763 /**
2764  * mono_framework_version:
2765  *
2766  * Return the major version of the framework curently executing.
2767  */
2768 int
2769 mono_framework_version (void)
2770 {
2771         return current_runtime->framework_version [0] - '0';
2772 }
2773
2774 void
2775 mono_enable_debug_domain_unload (gboolean enable)
2776 {
2777         debug_domain_unload = enable;
2778 }