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