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