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