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