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