[runtime] Factor out some duplicate code from the MonoJitInfo creation code.
[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 int
894 mono_jit_info_size (MonoJitInfoFlags flags, int num_clauses, int num_holes)
895 {
896         int size = MONO_SIZEOF_JIT_INFO;
897
898         size += num_clauses * sizeof (MonoJitExceptionInfo);
899         if (flags & JIT_INFO_HAS_CAS_INFO)
900                 size += sizeof (MonoMethodCasInfo);
901         if (flags & JIT_INFO_HAS_GENERIC_JIT_INFO)
902                 size += sizeof (MonoGenericJitInfo);
903         if (flags & JIT_INFO_HAS_TRY_BLOCK_HOLES)
904                 size += sizeof (MonoTryBlockHoleTableJitInfo) + num_holes * sizeof (MonoTryBlockHoleJitInfo);
905         if (flags & JIT_INFO_HAS_ARCH_EH_INFO)
906                 size += sizeof (MonoArchEHJitInfo);
907         return size;
908 }
909
910 void
911 mono_jit_info_init (MonoJitInfo *ji, MonoMethod *method, guint8 *code, int code_size,
912                                         MonoJitInfoFlags flags, int num_clauses, int num_holes)
913 {
914         ji->d.method = method;
915         ji->code_start = code;
916         ji->code_size = code_size;
917         ji->num_clauses = num_clauses;
918         if (flags & JIT_INFO_HAS_CAS_INFO)
919                 ji->has_cas_info = 1;
920         if (flags & JIT_INFO_HAS_GENERIC_JIT_INFO)
921                 ji->has_generic_jit_info = 1;
922         if (flags & JIT_INFO_HAS_TRY_BLOCK_HOLES)
923                 ji->has_try_block_holes = 1;
924         if (flags & JIT_INFO_HAS_ARCH_EH_INFO)
925                 ji->has_arch_eh_info = 1;
926 }
927
928 gpointer
929 mono_jit_info_get_code_start (MonoJitInfo* ji)
930 {
931         return ji->code_start;
932 }
933
934 int
935 mono_jit_info_get_code_size (MonoJitInfo* ji)
936 {
937         return ji->code_size;
938 }
939
940 MonoMethod*
941 mono_jit_info_get_method (MonoJitInfo* ji)
942 {
943         g_assert (!ji->async);
944         return ji->d.method;
945 }
946
947 static gpointer
948 jit_info_key_extract (gpointer value)
949 {
950         MonoJitInfo *info = (MonoJitInfo*)value;
951
952         return info->d.method;
953 }
954
955 static gpointer*
956 jit_info_next_value (gpointer value)
957 {
958         MonoJitInfo *info = (MonoJitInfo*)value;
959
960         return (gpointer*)&info->next_jit_code_hash;
961 }
962
963 void
964 mono_jit_code_hash_init (MonoInternalHashTable *jit_code_hash)
965 {
966         mono_internal_hash_table_init (jit_code_hash,
967                                        mono_aligned_addr_hash,
968                                        jit_info_key_extract,
969                                        jit_info_next_value);
970 }
971
972 MonoGenericJitInfo*
973 mono_jit_info_get_generic_jit_info (MonoJitInfo *ji)
974 {
975         if (ji->has_generic_jit_info)
976                 return (MonoGenericJitInfo*)&ji->clauses [ji->num_clauses];
977         else
978                 return NULL;
979 }
980
981 /*
982  * mono_jit_info_get_generic_sharing_context:
983  * @ji: a jit info
984  *
985  * Returns the jit info's generic sharing context, or NULL if it
986  * doesn't have one.
987  */
988 MonoGenericSharingContext*
989 mono_jit_info_get_generic_sharing_context (MonoJitInfo *ji)
990 {
991         MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
992
993         if (gi)
994                 return gi->generic_sharing_context;
995         else
996                 return NULL;
997 }
998
999 /*
1000  * mono_jit_info_set_generic_sharing_context:
1001  * @ji: a jit info
1002  * @gsctx: a generic sharing context
1003  *
1004  * Sets the jit info's generic sharing context.  The jit info must
1005  * have memory allocated for the context.
1006  */
1007 void
1008 mono_jit_info_set_generic_sharing_context (MonoJitInfo *ji, MonoGenericSharingContext *gsctx)
1009 {
1010         MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
1011
1012         g_assert (gi);
1013
1014         gi->generic_sharing_context = gsctx;
1015 }
1016
1017 MonoTryBlockHoleTableJitInfo*
1018 mono_jit_info_get_try_block_hole_table_info (MonoJitInfo *ji)
1019 {
1020         if (ji->has_try_block_holes) {
1021                 char *ptr = (char*)&ji->clauses [ji->num_clauses];
1022                 if (ji->has_generic_jit_info)
1023                         ptr += sizeof (MonoGenericJitInfo);
1024                 return (MonoTryBlockHoleTableJitInfo*)ptr;
1025         } else {
1026                 return NULL;
1027         }
1028 }
1029
1030 static int
1031 try_block_hole_table_size (MonoJitInfo *ji)
1032 {
1033         MonoTryBlockHoleTableJitInfo *table;
1034
1035         table = mono_jit_info_get_try_block_hole_table_info (ji);
1036         g_assert (table);
1037         return sizeof (MonoTryBlockHoleTableJitInfo) + table->num_holes * sizeof (MonoTryBlockHoleJitInfo);
1038 }
1039
1040 MonoArchEHJitInfo*
1041 mono_jit_info_get_arch_eh_info (MonoJitInfo *ji)
1042 {
1043         if (ji->has_arch_eh_info) {
1044                 char *ptr = (char*)&ji->clauses [ji->num_clauses];
1045                 if (ji->has_generic_jit_info)
1046                         ptr += sizeof (MonoGenericJitInfo);
1047                 if (ji->has_try_block_holes)
1048                         ptr += try_block_hole_table_size (ji);
1049                 return (MonoArchEHJitInfo*)ptr;
1050         } else {
1051                 return NULL;
1052         }
1053 }
1054
1055 MonoMethodCasInfo*
1056 mono_jit_info_get_cas_info (MonoJitInfo *ji)
1057 {
1058         if (ji->has_cas_info) {
1059                 char *ptr = (char*)&ji->clauses [ji->num_clauses];
1060                 if (ji->has_generic_jit_info)
1061                         ptr += sizeof (MonoGenericJitInfo);
1062                 if (ji->has_try_block_holes)
1063                         ptr += try_block_hole_table_size (ji);
1064                 if (ji->has_arch_eh_info)
1065                         ptr += sizeof (MonoArchEHJitInfo);
1066                 return (MonoMethodCasInfo*)ptr;
1067         } else {
1068                 return NULL;
1069         }
1070 }
1071
1072 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
1073 #define ALIGN_PTR_TO(ptr,align) (gpointer)((((gssize)(ptr)) + (align - 1)) & (~(align - 1)))
1074
1075 static LockFreeMempool*
1076 lock_free_mempool_new (void)
1077 {
1078         return g_new0 (LockFreeMempool, 1);
1079 }
1080
1081 static void
1082 lock_free_mempool_free (LockFreeMempool *mp)
1083 {
1084         LockFreeMempoolChunk *chunk, *next;
1085
1086         chunk = mp->chunks;
1087         while (chunk) {
1088                 next = chunk->prev;
1089                 mono_vfree (chunk, mono_pagesize ());
1090                 chunk = next;
1091         }
1092         g_free (mp);
1093 }
1094
1095 /*
1096  * This is async safe
1097  */
1098 static LockFreeMempoolChunk*
1099 lock_free_mempool_chunk_new (LockFreeMempool *mp, int len)
1100 {
1101         LockFreeMempoolChunk *chunk, *prev;
1102         int size;
1103
1104         size = mono_pagesize ();
1105         while (size - sizeof (LockFreeMempoolChunk) < len)
1106                 size += mono_pagesize ();
1107         chunk = mono_valloc (0, size, MONO_MMAP_READ|MONO_MMAP_WRITE);
1108         g_assert (chunk);
1109         chunk->mem = ALIGN_PTR_TO ((char*)chunk + sizeof (LockFreeMempoolChunk), 16);
1110         chunk->size = ((char*)chunk + size) - (char*)chunk->mem;
1111         chunk->pos = 0;
1112
1113         /* Add to list of chunks lock-free */
1114         while (TRUE) {
1115                 prev = mp->chunks;
1116                 if (InterlockedCompareExchangePointer ((volatile gpointer*)&mp->chunks, chunk, prev) == prev)
1117                         break;
1118         }
1119         chunk->prev = prev;
1120
1121         return chunk;
1122 }
1123
1124 /*
1125  * This is async safe
1126  */
1127 static gpointer
1128 lock_free_mempool_alloc0 (LockFreeMempool *mp, guint size)
1129 {
1130         LockFreeMempoolChunk *chunk;
1131         gpointer res;
1132         int oldpos;
1133
1134         // FIXME: Free the allocator
1135
1136         size = ALIGN_TO (size, 8);
1137         chunk = mp->current;
1138         if (!chunk) {
1139                 chunk = lock_free_mempool_chunk_new (mp, size);
1140                 mono_memory_barrier ();
1141                 /* Publish */
1142                 mp->current = chunk;
1143         }
1144
1145         /* The code below is lock-free, 'chunk' is shared state */
1146         oldpos = InterlockedExchangeAdd (&chunk->pos, size);
1147         if (oldpos + size > chunk->size) {
1148                 chunk = lock_free_mempool_chunk_new (mp, size);
1149                 g_assert (chunk->pos + size <= chunk->size);
1150                 res = chunk->mem;
1151                 chunk->pos += size;
1152                 mono_memory_barrier ();
1153                 mp->current = chunk;
1154         } else {
1155                 res = (char*)chunk->mem + oldpos;
1156         }
1157
1158         return res;
1159 }
1160
1161 void
1162 mono_install_create_domain_hook (MonoCreateDomainFunc func)
1163 {
1164         create_domain_hook = func;
1165 }
1166
1167 void
1168 mono_install_free_domain_hook (MonoFreeDomainFunc func)
1169 {
1170         free_domain_hook = func;
1171 }
1172
1173 /**
1174  * mono_string_equal:
1175  * @s1: First string to compare
1176  * @s2: Second string to compare
1177  *
1178  * Returns FALSE if the strings differ.
1179  */
1180 gboolean
1181 mono_string_equal (MonoString *s1, MonoString *s2)
1182 {
1183         int l1 = mono_string_length (s1);
1184         int l2 = mono_string_length (s2);
1185
1186         if (s1 == s2)
1187                 return TRUE;
1188         if (l1 != l2)
1189                 return FALSE;
1190
1191         return memcmp (mono_string_chars (s1), mono_string_chars (s2), l1 * 2) == 0; 
1192 }
1193
1194 /**
1195  * mono_string_hash:
1196  * @s: the string to hash
1197  *
1198  * Returns the hash for the string.
1199  */
1200 guint
1201 mono_string_hash (MonoString *s)
1202 {
1203         const guint16 *p = mono_string_chars (s);
1204         int i, len = mono_string_length (s);
1205         guint h = 0;
1206
1207         for (i = 0; i < len; i++) {
1208                 h = (h << 5) - h + *p;
1209                 p++;
1210         }
1211
1212         return h;       
1213 }
1214
1215 static gboolean
1216 mono_ptrarray_equal (gpointer *s1, gpointer *s2)
1217 {
1218         int len = GPOINTER_TO_INT (s1 [0]);
1219         if (len != GPOINTER_TO_INT (s2 [0]))
1220                 return FALSE;
1221
1222         return memcmp (s1 + 1, s2 + 1, len * sizeof(gpointer)) == 0; 
1223 }
1224
1225 static guint
1226 mono_ptrarray_hash (gpointer *s)
1227 {
1228         int i;
1229         int len = GPOINTER_TO_INT (s [0]);
1230         guint hash = 0;
1231         
1232         for (i = 1; i < len; i++)
1233                 hash += GPOINTER_TO_UINT (s [i]);
1234
1235         return hash;    
1236 }
1237
1238 /*
1239  * Allocate an id for domain and set domain->domain_id.
1240  * LOCKING: must be called while holding appdomains_mutex.
1241  * We try to assign low numbers to the domain, so it can be used
1242  * as an index in data tables to lookup domain-specific info
1243  * with minimal memory overhead. We also try not to reuse the
1244  * same id too quickly (to help debugging).
1245  */
1246 static int
1247 domain_id_alloc (MonoDomain *domain)
1248 {
1249         int id = -1, i;
1250         if (!appdomains_list) {
1251                 appdomain_list_size = 2;
1252                 appdomains_list = mono_gc_alloc_fixed (appdomain_list_size * sizeof (void*), NULL);
1253         }
1254         for (i = appdomain_next; i < appdomain_list_size; ++i) {
1255                 if (!appdomains_list [i]) {
1256                         id = i;
1257                         break;
1258                 }
1259         }
1260         if (id == -1) {
1261                 for (i = 0; i < appdomain_next; ++i) {
1262                         if (!appdomains_list [i]) {
1263                                 id = i;
1264                                 break;
1265                         }
1266                 }
1267         }
1268         if (id == -1) {
1269                 MonoDomain **new_list;
1270                 int new_size = appdomain_list_size * 2;
1271                 if (new_size >= (1 << 16))
1272                         g_assert_not_reached ();
1273                 id = appdomain_list_size;
1274                 new_list = mono_gc_alloc_fixed (new_size * sizeof (void*), NULL);
1275                 memcpy (new_list, appdomains_list, appdomain_list_size * sizeof (void*));
1276                 mono_gc_free_fixed (appdomains_list);
1277                 appdomains_list = new_list;
1278                 appdomain_list_size = new_size;
1279         }
1280         domain->domain_id = id;
1281         appdomains_list [id] = domain;
1282         appdomain_next++;
1283         if (appdomain_next > appdomain_list_size)
1284                 appdomain_next = 0;
1285         return id;
1286 }
1287
1288 static gsize domain_gc_bitmap [sizeof(MonoDomain)/4/32 + 1];
1289 static gpointer domain_gc_desc = NULL;
1290 static guint32 domain_shadow_serial = 0L;
1291
1292 MonoDomain *
1293 mono_domain_create (void)
1294 {
1295         MonoDomain *domain;
1296         guint32 shadow_serial;
1297   
1298         mono_appdomains_lock ();
1299         shadow_serial = domain_shadow_serial++;
1300   
1301         if (!domain_gc_desc) {
1302                 unsigned int i, bit = 0;
1303                 for (i = G_STRUCT_OFFSET (MonoDomain, MONO_DOMAIN_FIRST_OBJECT); i < G_STRUCT_OFFSET (MonoDomain, MONO_DOMAIN_FIRST_GC_TRACKED); i += sizeof (gpointer)) {
1304                         bit = i / sizeof (gpointer);
1305                         domain_gc_bitmap [bit / 32] |= (gsize) 1 << (bit % 32);
1306                 }
1307                 domain_gc_desc = mono_gc_make_descr_from_bitmap ((gsize*)domain_gc_bitmap, bit + 1);
1308         }
1309         mono_appdomains_unlock ();
1310
1311 #ifdef HAVE_BOEHM_GC
1312         /*
1313          * Boehm doesn't like roots inside GC allocated objects, and alloc_fixed returns
1314          * a GC_MALLOC-ed object, contrary to the api docs. This causes random crashes when
1315          * running the corlib test suite.
1316          * To solve this, we pass a NULL descriptor, and don't register roots.
1317          */
1318         domain = mono_gc_alloc_fixed (sizeof (MonoDomain), NULL);
1319 #else
1320         domain = mono_gc_alloc_fixed (sizeof (MonoDomain), domain_gc_desc);
1321         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);
1322 #endif
1323         domain->shadow_serial = shadow_serial;
1324         domain->domain = NULL;
1325         domain->setup = NULL;
1326         domain->friendly_name = NULL;
1327         domain->search_path = NULL;
1328
1329         mono_profiler_appdomain_event (domain, MONO_PROFILE_START_LOAD);
1330
1331         domain->mp = mono_mempool_new ();
1332         domain->code_mp = mono_code_manager_new ();
1333         domain->lock_free_mp = lock_free_mempool_new ();
1334         domain->env = mono_g_hash_table_new_type ((GHashFunc)mono_string_hash, (GCompareFunc)mono_string_equal, MONO_HASH_KEY_VALUE_GC);
1335         domain->domain_assemblies = NULL;
1336         domain->assembly_bindings = NULL;
1337         domain->assembly_bindings_parsed = FALSE;
1338         domain->class_vtable_array = g_ptr_array_new ();
1339         domain->proxy_vtable_hash = g_hash_table_new ((GHashFunc)mono_ptrarray_hash, (GCompareFunc)mono_ptrarray_equal);
1340         domain->static_data_array = NULL;
1341         mono_jit_code_hash_init (&domain->jit_code_hash);
1342         domain->ldstr_table = mono_g_hash_table_new_type ((GHashFunc)mono_string_hash, (GCompareFunc)mono_string_equal, MONO_HASH_KEY_VALUE_GC);
1343         domain->num_jit_info_tables = 1;
1344         domain->jit_info_table = jit_info_table_new (domain);
1345         domain->jit_info_free_queue = NULL;
1346         domain->finalizable_objects_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1347         domain->ftnptrs_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1348
1349         mono_mutex_init_recursive (&domain->lock);
1350         mono_mutex_init_recursive (&domain->assemblies_lock);
1351         mono_mutex_init_recursive (&domain->jit_code_hash_lock);
1352         mono_mutex_init_recursive (&domain->finalizable_objects_hash_lock);
1353
1354         domain->method_rgctx_hash = NULL;
1355
1356         mono_appdomains_lock ();
1357         domain_id_alloc (domain);
1358         mono_appdomains_unlock ();
1359
1360 #ifndef DISABLE_PERFCOUNTERS
1361         mono_perfcounters->loader_appdomains++;
1362         mono_perfcounters->loader_total_appdomains++;
1363 #endif
1364
1365         mono_debug_domain_create (domain);
1366
1367         if (create_domain_hook)
1368                 create_domain_hook (domain);
1369
1370         mono_profiler_appdomain_loaded (domain, MONO_PROFILE_OK);
1371         
1372         return domain;
1373 }
1374
1375 /**
1376  * mono_init_internal:
1377  * 
1378  * Creates the initial application domain and initializes the mono_defaults
1379  * structure.
1380  * This function is guaranteed to not run any IL code.
1381  * If exe_filename is not NULL, the method will determine the required runtime
1382  * from the exe configuration file or the version PE field.
1383  * If runtime_version is not NULL, that runtime version will be used.
1384  * Either exe_filename or runtime_version must be provided.
1385  *
1386  * Returns: the initial domain.
1387  */
1388 static MonoDomain *
1389 mono_init_internal (const char *filename, const char *exe_filename, const char *runtime_version)
1390 {
1391         static MonoDomain *domain = NULL;
1392         MonoAssembly *ass = NULL;
1393         MonoImageOpenStatus status = MONO_IMAGE_OK;
1394         const MonoRuntimeInfo* runtimes [G_N_ELEMENTS (supported_runtimes) + 1];
1395         int n;
1396
1397 #ifdef DEBUG_DOMAIN_UNLOAD
1398         debug_domain_unload = TRUE;
1399 #endif
1400
1401         if (domain)
1402                 g_assert_not_reached ();
1403
1404 #ifdef HOST_WIN32
1405         /* Avoid system error message boxes. */
1406         SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
1407 #endif
1408
1409 #ifndef HOST_WIN32
1410         wapi_init ();
1411 #endif
1412
1413 #ifndef DISABLE_PERFCOUNTERS
1414         mono_perfcounters_init ();
1415 #endif
1416
1417         mono_counters_register ("Max native code in a domain", MONO_COUNTER_INT|MONO_COUNTER_JIT, &max_domain_code_size);
1418         mono_counters_register ("Max code space allocated in a domain", MONO_COUNTER_INT|MONO_COUNTER_JIT, &max_domain_code_alloc);
1419         mono_counters_register ("Total code space allocated", MONO_COUNTER_INT|MONO_COUNTER_JIT, &total_domain_code_alloc);
1420
1421         mono_gc_base_init ();
1422
1423         MONO_FAST_TLS_INIT (tls_appdomain);
1424         mono_native_tls_alloc (&appdomain_thread_id, NULL);
1425
1426         mono_mutex_init_recursive (&appdomains_mutex);
1427
1428         mono_metadata_init ();
1429         mono_images_init ();
1430         mono_assemblies_init ();
1431         mono_classes_init ();
1432         mono_loader_init ();
1433         mono_reflection_init ();
1434         mono_runtime_init_tls ();
1435
1436         /* FIXME: When should we release this memory? */
1437         MONO_GC_REGISTER_ROOT_FIXED (appdomains_list);
1438
1439         domain = mono_domain_create ();
1440         mono_root_domain = domain;
1441
1442         SET_APPDOMAIN (domain);
1443         
1444         /* Get a list of runtimes supported by the exe */
1445         if (exe_filename != NULL) {
1446                 /*
1447                  * This function will load the exe file as a MonoImage. We need to close it, but
1448                  * that would mean it would be reloaded later. So instead, we save it to
1449                  * exe_image, and close it during shutdown.
1450                  */
1451                 get_runtimes_from_exe (exe_filename, &exe_image, runtimes);
1452 #ifdef HOST_WIN32
1453                 if (!exe_image) {
1454                         exe_image = mono_assembly_open_from_bundle (exe_filename, NULL, FALSE);
1455                         if (!exe_image)
1456                                 exe_image = mono_image_open (exe_filename, NULL);
1457                 }
1458                 mono_fixup_exe_image (exe_image);
1459 #endif
1460         } else if (runtime_version != NULL) {
1461                 runtimes [0] = get_runtime_by_version (runtime_version);
1462                 runtimes [1] = NULL;
1463         }
1464
1465         if (runtimes [0] == NULL) {
1466                 const MonoRuntimeInfo *default_runtime = get_runtime_by_version (DEFAULT_RUNTIME_VERSION);
1467                 runtimes [0] = default_runtime;
1468                 runtimes [1] = NULL;
1469                 g_print ("WARNING: The runtime version supported by this application is unavailable.\n");
1470                 g_print ("Using default runtime: %s\n", default_runtime->runtime_version); 
1471         }
1472
1473         /* The selected runtime will be the first one for which there is a mscrolib.dll */
1474         for (n = 0; runtimes [n] != NULL && ass == NULL; n++) {
1475                 current_runtime = runtimes [n];
1476                 ass = mono_assembly_load_corlib (current_runtime, &status);
1477                 if (status != MONO_IMAGE_OK && status != MONO_IMAGE_ERROR_ERRNO)
1478                         break;
1479
1480         }
1481         
1482         if ((status != MONO_IMAGE_OK) || (ass == NULL)) {
1483                 switch (status){
1484                 case MONO_IMAGE_ERROR_ERRNO: {
1485                         char *corlib_file = g_build_filename (mono_assembly_getrootdir (), "mono", current_runtime->framework_version, "mscorlib.dll", NULL);
1486                         g_print ("The assembly mscorlib.dll was not found or could not be loaded.\n");
1487                         g_print ("It should have been installed in the `%s' directory.\n", corlib_file);
1488                         g_free (corlib_file);
1489                         break;
1490                 }
1491                 case MONO_IMAGE_IMAGE_INVALID:
1492                         g_print ("The file %s/mscorlib.dll is an invalid CIL image\n",
1493                                  mono_assembly_getrootdir ());
1494                         break;
1495                 case MONO_IMAGE_MISSING_ASSEMBLYREF:
1496                         g_print ("Missing assembly reference in %s/mscorlib.dll\n",
1497                                  mono_assembly_getrootdir ());
1498                         break;
1499                 case MONO_IMAGE_OK:
1500                         /* to suppress compiler warning */
1501                         break;
1502                 }
1503                 
1504                 exit (1);
1505         }
1506         mono_defaults.corlib = mono_assembly_get_image (ass);
1507
1508         mono_defaults.object_class = mono_class_from_name (
1509                 mono_defaults.corlib, "System", "Object");
1510         g_assert (mono_defaults.object_class != 0);
1511
1512         mono_defaults.void_class = mono_class_from_name (
1513                 mono_defaults.corlib, "System", "Void");
1514         g_assert (mono_defaults.void_class != 0);
1515
1516         mono_defaults.boolean_class = mono_class_from_name (
1517                 mono_defaults.corlib, "System", "Boolean");
1518         g_assert (mono_defaults.boolean_class != 0);
1519
1520         mono_defaults.byte_class = mono_class_from_name (
1521                 mono_defaults.corlib, "System", "Byte");
1522         g_assert (mono_defaults.byte_class != 0);
1523
1524         mono_defaults.sbyte_class = mono_class_from_name (
1525                 mono_defaults.corlib, "System", "SByte");
1526         g_assert (mono_defaults.sbyte_class != 0);
1527
1528         mono_defaults.int16_class = mono_class_from_name (
1529                 mono_defaults.corlib, "System", "Int16");
1530         g_assert (mono_defaults.int16_class != 0);
1531
1532         mono_defaults.uint16_class = mono_class_from_name (
1533                 mono_defaults.corlib, "System", "UInt16");
1534         g_assert (mono_defaults.uint16_class != 0);
1535
1536         mono_defaults.int32_class = mono_class_from_name (
1537                 mono_defaults.corlib, "System", "Int32");
1538         g_assert (mono_defaults.int32_class != 0);
1539
1540         mono_defaults.uint32_class = mono_class_from_name (
1541                 mono_defaults.corlib, "System", "UInt32");
1542         g_assert (mono_defaults.uint32_class != 0);
1543
1544         mono_defaults.uint_class = mono_class_from_name (
1545                 mono_defaults.corlib, "System", "UIntPtr");
1546         g_assert (mono_defaults.uint_class != 0);
1547
1548         mono_defaults.int_class = mono_class_from_name (
1549                 mono_defaults.corlib, "System", "IntPtr");
1550         g_assert (mono_defaults.int_class != 0);
1551
1552         mono_defaults.int64_class = mono_class_from_name (
1553                 mono_defaults.corlib, "System", "Int64");
1554         g_assert (mono_defaults.int64_class != 0);
1555
1556         mono_defaults.uint64_class = mono_class_from_name (
1557                 mono_defaults.corlib, "System", "UInt64");
1558         g_assert (mono_defaults.uint64_class != 0);
1559
1560         mono_defaults.single_class = mono_class_from_name (
1561                 mono_defaults.corlib, "System", "Single");
1562         g_assert (mono_defaults.single_class != 0);
1563
1564         mono_defaults.double_class = mono_class_from_name (
1565                 mono_defaults.corlib, "System", "Double");
1566         g_assert (mono_defaults.double_class != 0);
1567
1568         mono_defaults.char_class = mono_class_from_name (
1569                 mono_defaults.corlib, "System", "Char");
1570         g_assert (mono_defaults.char_class != 0);
1571
1572         mono_defaults.string_class = mono_class_from_name (
1573                 mono_defaults.corlib, "System", "String");
1574         g_assert (mono_defaults.string_class != 0);
1575
1576         mono_defaults.enum_class = mono_class_from_name (
1577                 mono_defaults.corlib, "System", "Enum");
1578         g_assert (mono_defaults.enum_class != 0);
1579
1580         mono_defaults.array_class = mono_class_from_name (
1581                 mono_defaults.corlib, "System", "Array");
1582         g_assert (mono_defaults.array_class != 0);
1583
1584         mono_defaults.delegate_class = mono_class_from_name (
1585                 mono_defaults.corlib, "System", "Delegate");
1586         g_assert (mono_defaults.delegate_class != 0 );
1587
1588         mono_defaults.multicastdelegate_class = mono_class_from_name (
1589                 mono_defaults.corlib, "System", "MulticastDelegate");
1590         g_assert (mono_defaults.multicastdelegate_class != 0 );
1591
1592         mono_defaults.asyncresult_class = mono_class_from_name (
1593                 mono_defaults.corlib, "System.Runtime.Remoting.Messaging", 
1594                 "AsyncResult");
1595         g_assert (mono_defaults.asyncresult_class != 0 );
1596
1597         mono_defaults.manualresetevent_class = mono_class_from_name (
1598                 mono_defaults.corlib, "System.Threading", "ManualResetEvent");
1599         g_assert (mono_defaults.manualresetevent_class != 0 );
1600
1601         mono_defaults.typehandle_class = mono_class_from_name (
1602                 mono_defaults.corlib, "System", "RuntimeTypeHandle");
1603         g_assert (mono_defaults.typehandle_class != 0);
1604
1605         mono_defaults.methodhandle_class = mono_class_from_name (
1606                 mono_defaults.corlib, "System", "RuntimeMethodHandle");
1607         g_assert (mono_defaults.methodhandle_class != 0);
1608
1609         mono_defaults.fieldhandle_class = mono_class_from_name (
1610                 mono_defaults.corlib, "System", "RuntimeFieldHandle");
1611         g_assert (mono_defaults.fieldhandle_class != 0);
1612
1613         mono_defaults.systemtype_class = mono_class_from_name (
1614                 mono_defaults.corlib, "System", "Type");
1615         g_assert (mono_defaults.systemtype_class != 0);
1616
1617         mono_defaults.monotype_class = mono_class_from_name (
1618                 mono_defaults.corlib, "System", "MonoType");
1619         g_assert (mono_defaults.monotype_class != 0);
1620
1621         mono_defaults.exception_class = mono_class_from_name (
1622                 mono_defaults.corlib, "System", "Exception");
1623         g_assert (mono_defaults.exception_class != 0);
1624
1625         mono_defaults.threadabortexception_class = mono_class_from_name (
1626                 mono_defaults.corlib, "System.Threading", "ThreadAbortException");
1627         g_assert (mono_defaults.threadabortexception_class != 0);
1628
1629         mono_defaults.thread_class = mono_class_from_name (
1630                 mono_defaults.corlib, "System.Threading", "Thread");
1631         g_assert (mono_defaults.thread_class != 0);
1632
1633         mono_defaults.internal_thread_class = mono_class_from_name (
1634                 mono_defaults.corlib, "System.Threading", "InternalThread");
1635         if (!mono_defaults.internal_thread_class) {
1636                 /* This can happen with an old mscorlib */
1637                 fprintf (stderr, "Corlib too old for this runtime.\n");
1638                 fprintf (stderr, "Loaded from: %s\n",
1639                                  mono_defaults.corlib? mono_image_get_filename (mono_defaults.corlib): "unknown");
1640                 exit (1);
1641         }
1642
1643         mono_defaults.appdomain_class = mono_class_from_name (
1644                 mono_defaults.corlib, "System", "AppDomain");
1645         g_assert (mono_defaults.appdomain_class != 0);
1646
1647 #ifndef DISABLE_REMOTING
1648         mono_defaults.transparent_proxy_class = mono_class_from_name (
1649                 mono_defaults.corlib, "System.Runtime.Remoting.Proxies", "TransparentProxy");
1650         g_assert (mono_defaults.transparent_proxy_class != 0);
1651
1652         mono_defaults.real_proxy_class = mono_class_from_name (
1653                 mono_defaults.corlib, "System.Runtime.Remoting.Proxies", "RealProxy");
1654         g_assert (mono_defaults.real_proxy_class != 0);
1655
1656         mono_defaults.marshalbyrefobject_class =  mono_class_from_name (
1657                 mono_defaults.corlib, "System", "MarshalByRefObject");
1658         g_assert (mono_defaults.marshalbyrefobject_class != 0);
1659
1660         mono_defaults.iremotingtypeinfo_class = mono_class_from_name (
1661                 mono_defaults.corlib, "System.Runtime.Remoting", "IRemotingTypeInfo");
1662         g_assert (mono_defaults.iremotingtypeinfo_class != 0);
1663 #endif
1664
1665         mono_defaults.mono_method_message_class = mono_class_from_name (
1666                 mono_defaults.corlib, "System.Runtime.Remoting.Messaging", "MonoMethodMessage");
1667         g_assert (mono_defaults.mono_method_message_class != 0);
1668
1669         mono_defaults.field_info_class = mono_class_from_name (
1670                 mono_defaults.corlib, "System.Reflection", "FieldInfo");
1671         g_assert (mono_defaults.field_info_class != 0);
1672
1673         mono_defaults.method_info_class = mono_class_from_name (
1674                 mono_defaults.corlib, "System.Reflection", "MethodInfo");
1675         g_assert (mono_defaults.method_info_class != 0);
1676
1677         mono_defaults.stringbuilder_class = mono_class_from_name (
1678                 mono_defaults.corlib, "System.Text", "StringBuilder");
1679         g_assert (mono_defaults.stringbuilder_class != 0);
1680
1681         mono_defaults.math_class = mono_class_from_name (
1682                 mono_defaults.corlib, "System", "Math");
1683         g_assert (mono_defaults.math_class != 0);
1684
1685         mono_defaults.stack_frame_class = mono_class_from_name (
1686                 mono_defaults.corlib, "System.Diagnostics", "StackFrame");
1687         g_assert (mono_defaults.stack_frame_class != 0);
1688
1689         mono_defaults.stack_trace_class = mono_class_from_name (
1690                 mono_defaults.corlib, "System.Diagnostics", "StackTrace");
1691         g_assert (mono_defaults.stack_trace_class != 0);
1692
1693         mono_defaults.marshal_class = mono_class_from_name (
1694                 mono_defaults.corlib, "System.Runtime.InteropServices", "Marshal");
1695         g_assert (mono_defaults.marshal_class != 0);
1696
1697         mono_defaults.typed_reference_class =  mono_class_from_name (
1698                 mono_defaults.corlib, "System", "TypedReference");
1699         g_assert (mono_defaults.typed_reference_class != 0);
1700
1701         mono_defaults.argumenthandle_class =  mono_class_from_name (
1702                 mono_defaults.corlib, "System", "RuntimeArgumentHandle");
1703         g_assert (mono_defaults.argumenthandle_class != 0);
1704
1705         mono_defaults.monitor_class =  mono_class_from_name (
1706                 mono_defaults.corlib, "System.Threading", "Monitor");
1707         g_assert (mono_defaults.monitor_class != 0);
1708
1709         mono_defaults.runtimesecurityframe_class = mono_class_from_name (
1710                 mono_defaults.corlib, "System.Security", "RuntimeSecurityFrame");
1711
1712         mono_defaults.executioncontext_class = mono_class_from_name (
1713                 mono_defaults.corlib, "System.Threading", "ExecutionContext");
1714
1715         mono_defaults.internals_visible_class = mono_class_from_name (
1716                 mono_defaults.corlib, "System.Runtime.CompilerServices", "InternalsVisibleToAttribute");
1717
1718         mono_defaults.critical_finalizer_object = mono_class_from_name (
1719                 mono_defaults.corlib, "System.Runtime.ConstrainedExecution", "CriticalFinalizerObject");
1720
1721         /*
1722          * mscorlib needs a little help, only now it can load its friends list (after we have
1723          * loaded the InternalsVisibleToAttribute), load it now
1724          */
1725         mono_assembly_load_friends (ass);
1726         
1727         mono_defaults.safehandle_class = mono_class_from_name (
1728                 mono_defaults.corlib, "System.Runtime.InteropServices", "SafeHandle");
1729
1730         mono_defaults.handleref_class = mono_class_from_name (
1731                 mono_defaults.corlib, "System.Runtime.InteropServices", "HandleRef");
1732
1733         mono_defaults.attribute_class = mono_class_from_name (
1734                 mono_defaults.corlib, "System", "Attribute");
1735
1736         mono_defaults.customattribute_data_class = mono_class_from_name (
1737                 mono_defaults.corlib, "System.Reflection", "CustomAttributeData");
1738
1739         /* these are initialized lazily when COM features are used */
1740
1741         mono_class_init (mono_defaults.array_class);
1742         mono_defaults.generic_nullable_class = mono_class_from_name (
1743                 mono_defaults.corlib, "System", "Nullable`1");
1744         mono_defaults.generic_ilist_class = mono_class_from_name (
1745                 mono_defaults.corlib, "System.Collections.Generic", "IList`1");
1746         mono_defaults.generic_ireadonlylist_class = mono_class_from_name (
1747                 mono_defaults.corlib, "System.Collections.Generic", "IReadOnlyList`1");
1748
1749         domain->friendly_name = g_path_get_basename (filename);
1750
1751         _mono_debug_init_corlib (domain);
1752
1753         return domain;
1754 }
1755
1756 /**
1757  * mono_init:
1758  * 
1759  * Creates the initial application domain and initializes the mono_defaults
1760  * structure.
1761  * This function is guaranteed to not run any IL code.
1762  * The runtime is initialized using the default runtime version.
1763  *
1764  * Returns: the initial domain.
1765  */
1766 MonoDomain *
1767 mono_init (const char *domain_name)
1768 {
1769         return mono_init_internal (domain_name, NULL, DEFAULT_RUNTIME_VERSION);
1770 }
1771
1772 /**
1773  * mono_init_from_assembly:
1774  * @domain_name: name to give to the initial domain
1775  * @filename: filename to load on startup
1776  *
1777  * Used by the runtime, users should use mono_jit_init instead.
1778  *
1779  * Creates the initial application domain and initializes the mono_defaults
1780  * structure.
1781  * This function is guaranteed to not run any IL code.
1782  * The runtime is initialized using the runtime version required by the
1783  * provided executable. The version is determined by looking at the exe 
1784  * configuration file and the version PE field)
1785  *
1786  * Returns: the initial domain.
1787  */
1788 MonoDomain *
1789 mono_init_from_assembly (const char *domain_name, const char *filename)
1790 {
1791         return mono_init_internal (domain_name, filename, NULL);
1792 }
1793
1794 /**
1795  * mono_init_version:
1796  * 
1797  * Used by the runtime, users should use mono_jit_init instead.
1798  * 
1799  * Creates the initial application domain and initializes the mono_defaults
1800  * structure.
1801  *
1802  * This function is guaranteed to not run any IL code.
1803  * The runtime is initialized using the provided rutime version.
1804  *
1805  * Returns: the initial domain.
1806  */
1807 MonoDomain *
1808 mono_init_version (const char *domain_name, const char *version)
1809 {
1810         return mono_init_internal (domain_name, NULL, version);
1811 }
1812
1813 /**
1814  * mono_cleanup:
1815  *
1816  * Cleans up all metadata modules. 
1817  */
1818 void
1819 mono_cleanup (void)
1820 {
1821         mono_close_exe_image ();
1822
1823         mono_defaults.corlib = NULL;
1824
1825         mono_config_cleanup ();
1826         mono_loader_cleanup ();
1827         mono_classes_cleanup ();
1828         mono_assemblies_cleanup ();
1829         mono_images_cleanup ();
1830         mono_debug_cleanup ();
1831         mono_metadata_cleanup ();
1832
1833         mono_native_tls_free (appdomain_thread_id);
1834         mono_mutex_destroy (&appdomains_mutex);
1835
1836 #ifndef HOST_WIN32
1837         wapi_cleanup ();
1838 #endif
1839 }
1840
1841 void
1842 mono_close_exe_image (void)
1843 {
1844         if (exe_image)
1845                 mono_image_close (exe_image);
1846 }
1847
1848 /**
1849  * mono_get_root_domain:
1850  *
1851  * The root AppDomain is the initial domain created by the runtime when it is
1852  * initialized.  Programs execute on this AppDomain, but can create new ones
1853  * later.   Currently there is no unmanaged API to create new AppDomains, this
1854  * must be done from managed code.
1855  *
1856  * Returns: the root appdomain, to obtain the current domain, use mono_domain_get ()
1857  */
1858 MonoDomain*
1859 mono_get_root_domain (void)
1860 {
1861         return mono_root_domain;
1862 }
1863
1864 /**
1865  * mono_domain_get:
1866  *
1867  * Returns: the current domain, to obtain the root domain use
1868  * mono_get_root_domain().
1869  */
1870 MonoDomain *
1871 mono_domain_get ()
1872 {
1873         return GET_APPDOMAIN ();
1874 }
1875
1876 void
1877 mono_domain_unset (void)
1878 {
1879         SET_APPDOMAIN (NULL);
1880 }
1881
1882 void
1883 mono_domain_set_internal_with_options (MonoDomain *domain, gboolean migrate_exception)
1884 {
1885         MonoInternalThread *thread;
1886
1887         if (mono_domain_get () == domain)
1888                 return;
1889
1890         SET_APPDOMAIN (domain);
1891         SET_APPCONTEXT (domain->default_context);
1892
1893         if (migrate_exception) {
1894                 thread = mono_thread_internal_current ();
1895                 if (!thread->abort_exc)
1896                         return;
1897
1898                 g_assert (thread->abort_exc->object.vtable->domain != domain);
1899                 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
1900                 g_assert (thread->abort_exc->object.vtable->domain == domain);
1901         }
1902 }
1903
1904 /**
1905  * mono_domain_set_internal:
1906  * @domain: the new domain
1907  *
1908  * Sets the current domain to @domain.
1909  */
1910 void
1911 mono_domain_set_internal (MonoDomain *domain)
1912 {
1913         mono_domain_set_internal_with_options (domain, TRUE);
1914 }
1915
1916 void
1917 mono_domain_foreach (MonoDomainFunc func, gpointer user_data)
1918 {
1919         int i, size;
1920         MonoDomain **copy;
1921
1922         /*
1923          * Create a copy of the data to avoid calling the user callback
1924          * inside the lock because that could lead to deadlocks.
1925          * We can do this because this function is not perf. critical.
1926          */
1927         mono_appdomains_lock ();
1928         size = appdomain_list_size;
1929         copy = mono_gc_alloc_fixed (appdomain_list_size * sizeof (void*), NULL);
1930         memcpy (copy, appdomains_list, appdomain_list_size * sizeof (void*));
1931         mono_appdomains_unlock ();
1932
1933         for (i = 0; i < size; ++i) {
1934                 if (copy [i])
1935                         func (copy [i], user_data);
1936         }
1937
1938         mono_gc_free_fixed (copy);
1939 }
1940
1941 /**
1942  * mono_domain_assembly_open:
1943  * @domain: the application domain
1944  * @name: file name of the assembly
1945  *
1946  * fixme: maybe we should integrate this with mono_assembly_open ??
1947  */
1948 MonoAssembly *
1949 mono_domain_assembly_open (MonoDomain *domain, const char *name)
1950 {
1951         MonoDomain *current;
1952         MonoAssembly *ass;
1953         GSList *tmp;
1954
1955         mono_domain_assemblies_lock (domain);
1956         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1957                 ass = tmp->data;
1958                 if (strcmp (name, ass->aname.name) == 0) {
1959                         mono_domain_assemblies_unlock (domain);
1960                         return ass;
1961                 }
1962         }
1963         mono_domain_assemblies_unlock (domain);
1964
1965         if (domain != mono_domain_get ()) {
1966                 current = mono_domain_get ();
1967
1968                 mono_domain_set (domain, FALSE);
1969                 ass = mono_assembly_open (name, NULL);
1970                 mono_domain_set (current, FALSE);
1971         } else {
1972                 ass = mono_assembly_open (name, NULL);
1973         }
1974
1975         return ass;
1976 }
1977
1978 static void
1979 unregister_vtable_reflection_type (MonoVTable *vtable)
1980 {
1981         MonoObject *type = vtable->type;
1982
1983         if (type->vtable->klass != mono_defaults.monotype_class)
1984                 MONO_GC_UNREGISTER_ROOT_IF_MOVING (vtable->type);
1985 }
1986
1987 void
1988 mono_domain_free (MonoDomain *domain, gboolean force)
1989 {
1990         int code_size, code_alloc;
1991         GSList *tmp;
1992         gpointer *p;
1993
1994         if ((domain == mono_root_domain) && !force) {
1995                 g_warning ("cant unload root domain");
1996                 return;
1997         }
1998
1999         if (mono_dont_free_domains)
2000                 return;
2001
2002         mono_profiler_appdomain_event (domain, MONO_PROFILE_START_UNLOAD);
2003
2004         mono_debug_domain_unload (domain);
2005
2006         mono_appdomains_lock ();
2007         appdomains_list [domain->domain_id] = NULL;
2008         mono_appdomains_unlock ();
2009
2010         /* must do this early as it accesses fields and types */
2011         if (domain->special_static_fields) {
2012                 mono_alloc_special_static_data_free (domain->special_static_fields);
2013                 g_hash_table_destroy (domain->special_static_fields);
2014                 domain->special_static_fields = NULL;
2015         }
2016
2017         /*
2018          * We must destroy all these hash tables here because they
2019          * contain references to managed objects belonging to the
2020          * domain.  Once we let the GC clear the domain there must be
2021          * no more such references, or we'll crash if a collection
2022          * occurs.
2023          */
2024         mono_g_hash_table_destroy (domain->ldstr_table);
2025         domain->ldstr_table = NULL;
2026
2027         mono_g_hash_table_destroy (domain->env);
2028         domain->env = NULL;
2029
2030         if (domain->tlsrec_list) {
2031                 mono_thread_destroy_domain_tls (domain);
2032                 domain->tlsrec_list = NULL;
2033         }
2034
2035         mono_reflection_cleanup_domain (domain);
2036
2037         /* This must be done before type_hash is freed */
2038         if (domain->class_vtable_array) {
2039                 int i;
2040                 for (i = 0; i < domain->class_vtable_array->len; ++i)
2041                         unregister_vtable_reflection_type (g_ptr_array_index (domain->class_vtable_array, i));
2042         }
2043
2044         if (domain->type_hash) {
2045                 mono_g_hash_table_destroy (domain->type_hash);
2046                 domain->type_hash = NULL;
2047         }
2048         if (domain->type_init_exception_hash) {
2049                 mono_g_hash_table_destroy (domain->type_init_exception_hash);
2050                 domain->type_init_exception_hash = NULL;
2051         }
2052
2053         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
2054                 MonoAssembly *ass = tmp->data;
2055                 mono_assembly_release_gc_roots (ass);
2056         }
2057
2058         /* Have to zero out reference fields since they will be invalidated by the clear_domain () call below */
2059         for (p = (gpointer*)&domain->MONO_DOMAIN_FIRST_OBJECT; p < (gpointer*)&domain->MONO_DOMAIN_FIRST_GC_TRACKED; ++p)
2060                 *p = NULL;
2061
2062         /* This needs to be done before closing assemblies */
2063         mono_gc_clear_domain (domain);
2064
2065         /* Close dynamic assemblies first, since they have no ref count */
2066         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
2067                 MonoAssembly *ass = tmp->data;
2068                 if (!ass->image || !image_is_dynamic (ass->image))
2069                         continue;
2070                 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);
2071                 if (!mono_assembly_close_except_image_pools (ass))
2072                         tmp->data = NULL;
2073         }
2074
2075         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
2076                 MonoAssembly *ass = tmp->data;
2077                 if (!ass)
2078                         continue;
2079                 if (!ass->image || image_is_dynamic (ass->image))
2080                         continue;
2081                 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);
2082                 if (!mono_assembly_close_except_image_pools (ass))
2083                         tmp->data = NULL;
2084         }
2085
2086         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
2087                 MonoAssembly *ass = tmp->data;
2088                 if (ass)
2089                         mono_assembly_close_finish (ass);
2090         }
2091         g_slist_free (domain->domain_assemblies);
2092         domain->domain_assemblies = NULL;
2093
2094         /* 
2095          * Send this after the assemblies have been unloaded and the domain is still in a 
2096          * usable state.
2097          */
2098         mono_profiler_appdomain_event (domain, MONO_PROFILE_END_UNLOAD);
2099
2100         if (free_domain_hook)
2101                 free_domain_hook (domain);
2102
2103         /* FIXME: free delegate_hash_table when it's used */
2104         if (domain->search_path) {
2105                 g_strfreev (domain->search_path);
2106                 domain->search_path = NULL;
2107         }
2108         domain->create_proxy_for_type_method = NULL;
2109         domain->private_invoke_method = NULL;
2110         domain->default_context = NULL;
2111         domain->out_of_memory_ex = NULL;
2112         domain->null_reference_ex = NULL;
2113         domain->stack_overflow_ex = NULL;
2114         domain->ephemeron_tombstone = NULL;
2115         domain->entry_assembly = NULL;
2116
2117         g_free (domain->friendly_name);
2118         domain->friendly_name = NULL;
2119         g_ptr_array_free (domain->class_vtable_array, TRUE);
2120         domain->class_vtable_array = NULL;
2121         g_hash_table_destroy (domain->proxy_vtable_hash);
2122         domain->proxy_vtable_hash = NULL;
2123         if (domain->static_data_array) {
2124                 mono_gc_free_fixed (domain->static_data_array);
2125                 domain->static_data_array = NULL;
2126         }
2127         mono_internal_hash_table_destroy (&domain->jit_code_hash);
2128
2129         /*
2130          * There might still be jit info tables of this domain which
2131          * are not freed.  Since the domain cannot be in use anymore,
2132          * this will free them.
2133          */
2134         mono_thread_hazardous_try_free_all ();
2135         if (domain->aot_modules)
2136                 jit_info_table_free (domain->aot_modules);
2137         g_assert (domain->num_jit_info_tables == 1);
2138         jit_info_table_free (domain->jit_info_table);
2139         domain->jit_info_table = NULL;
2140         g_assert (!domain->jit_info_free_queue);
2141
2142         /* collect statistics */
2143         code_alloc = mono_code_manager_size (domain->code_mp, &code_size);
2144         total_domain_code_alloc += code_alloc;
2145         max_domain_code_alloc = MAX (max_domain_code_alloc, code_alloc);
2146         max_domain_code_size = MAX (max_domain_code_size, code_size);
2147
2148         if (debug_domain_unload) {
2149                 mono_mempool_invalidate (domain->mp);
2150                 mono_code_manager_invalidate (domain->code_mp);
2151         } else {
2152 #ifndef DISABLE_PERFCOUNTERS
2153                 mono_perfcounters->loader_bytes -= mono_mempool_get_allocated (domain->mp);
2154 #endif
2155                 mono_mempool_destroy (domain->mp);
2156                 domain->mp = NULL;
2157                 mono_code_manager_destroy (domain->code_mp);
2158                 domain->code_mp = NULL;
2159         }
2160         lock_free_mempool_free (domain->lock_free_mp);
2161         domain->lock_free_mp = NULL;
2162
2163         g_hash_table_destroy (domain->finalizable_objects_hash);
2164         domain->finalizable_objects_hash = NULL;
2165         if (domain->method_rgctx_hash) {
2166                 g_hash_table_destroy (domain->method_rgctx_hash);
2167                 domain->method_rgctx_hash = NULL;
2168         }
2169         if (domain->generic_virtual_cases) {
2170                 g_hash_table_destroy (domain->generic_virtual_cases);
2171                 domain->generic_virtual_cases = NULL;
2172         }
2173         if (domain->generic_virtual_thunks) {
2174                 g_hash_table_destroy (domain->generic_virtual_thunks);
2175                 domain->generic_virtual_thunks = NULL;
2176         }
2177         if (domain->ftnptrs_hash) {
2178                 g_hash_table_destroy (domain->ftnptrs_hash);
2179                 domain->ftnptrs_hash = NULL;
2180         }
2181
2182         mono_mutex_destroy (&domain->finalizable_objects_hash_lock);
2183         mono_mutex_destroy (&domain->assemblies_lock);
2184         mono_mutex_destroy (&domain->jit_code_hash_lock);
2185         mono_mutex_destroy (&domain->lock);
2186         domain->setup = NULL;
2187
2188         mono_gc_deregister_root ((char*)&(domain->MONO_DOMAIN_FIRST_GC_TRACKED));
2189
2190         /* FIXME: anything else required ? */
2191
2192         mono_gc_free_fixed (domain);
2193
2194 #ifndef DISABLE_PERFCOUNTERS
2195         mono_perfcounters->loader_appdomains--;
2196 #endif
2197
2198         if (domain == mono_root_domain)
2199                 mono_root_domain = NULL;
2200 }
2201
2202 /**
2203  * mono_domain_get_id:
2204  * @domainid: the ID
2205  *
2206  * Returns: the a domain for a specific domain id.
2207  */
2208 MonoDomain * 
2209 mono_domain_get_by_id (gint32 domainid) 
2210 {
2211         MonoDomain * domain;
2212
2213         mono_appdomains_lock ();
2214         if (domainid < appdomain_list_size)
2215                 domain = appdomains_list [domainid];
2216         else
2217                 domain = NULL;
2218         mono_appdomains_unlock ();
2219
2220         return domain;
2221 }
2222
2223 gint32
2224 mono_domain_get_id (MonoDomain *domain)
2225 {
2226         return domain->domain_id;
2227 }
2228
2229 /*
2230  * mono_domain_alloc:
2231  *
2232  * LOCKING: Acquires the domain lock.
2233  */
2234 gpointer
2235 mono_domain_alloc (MonoDomain *domain, guint size)
2236 {
2237         gpointer res;
2238
2239         mono_domain_lock (domain);
2240 #ifndef DISABLE_PERFCOUNTERS
2241         mono_perfcounters->loader_bytes += size;
2242 #endif
2243         res = mono_mempool_alloc (domain->mp, size);
2244         mono_domain_unlock (domain);
2245
2246         return res;
2247 }
2248
2249 /*
2250  * mono_domain_alloc0:
2251  *
2252  * LOCKING: Acquires the domain lock.
2253  */
2254 gpointer
2255 mono_domain_alloc0 (MonoDomain *domain, guint size)
2256 {
2257         gpointer res;
2258
2259         mono_domain_lock (domain);
2260 #ifndef DISABLE_PERFCOUNTERS
2261         mono_perfcounters->loader_bytes += size;
2262 #endif
2263         res = mono_mempool_alloc0 (domain->mp, size);
2264         mono_domain_unlock (domain);
2265
2266         return res;
2267 }
2268
2269 gpointer
2270 mono_domain_alloc0_lock_free (MonoDomain *domain, guint size)
2271 {
2272         return lock_free_mempool_alloc0 (domain->lock_free_mp, size);
2273 }
2274
2275 /*
2276  * mono_domain_code_reserve:
2277  *
2278  * LOCKING: Acquires the domain lock.
2279  */
2280 void*
2281 mono_domain_code_reserve (MonoDomain *domain, int size)
2282 {
2283         gpointer res;
2284
2285         mono_domain_lock (domain);
2286         res = mono_code_manager_reserve (domain->code_mp, size);
2287         mono_domain_unlock (domain);
2288
2289         return res;
2290 }
2291
2292 /*
2293  * mono_domain_code_reserve_align:
2294  *
2295  * LOCKING: Acquires the domain lock.
2296  */
2297 void*
2298 mono_domain_code_reserve_align (MonoDomain *domain, int size, int alignment)
2299 {
2300         gpointer res;
2301
2302         mono_domain_lock (domain);
2303         res = mono_code_manager_reserve_align (domain->code_mp, size, alignment);
2304         mono_domain_unlock (domain);
2305
2306         return res;
2307 }
2308
2309 /*
2310  * mono_domain_code_commit:
2311  *
2312  * LOCKING: Acquires the domain lock.
2313  */
2314 void
2315 mono_domain_code_commit (MonoDomain *domain, void *data, int size, int newsize)
2316 {
2317         mono_domain_lock (domain);
2318         mono_code_manager_commit (domain->code_mp, data, size, newsize);
2319         mono_domain_unlock (domain);
2320 }
2321
2322 #if defined(__native_client_codegen__) && defined(__native_client__)
2323 /*
2324  * Given the temporary buffer (allocated by mono_domain_code_reserve) into which
2325  * we are generating code, return a pointer to the destination in the dynamic 
2326  * code segment into which the code will be copied when mono_domain_code_commit
2327  * is called.
2328  * LOCKING: Acquires the domain lock.
2329  */
2330 void *
2331 nacl_domain_get_code_dest (MonoDomain *domain, void *data)
2332 {
2333         void *dest;
2334         mono_domain_lock (domain);
2335         dest = nacl_code_manager_get_code_dest (domain->code_mp, data);
2336         mono_domain_unlock (domain);
2337         return dest;
2338 }
2339
2340 /* 
2341  * Convenience function which calls mono_domain_code_commit to validate and copy
2342  * the code. The caller sets *buf_base and *buf_size to the start and size of
2343  * the buffer (allocated by mono_domain_code_reserve), and *code_end to the byte
2344  * after the last instruction byte. On return, *buf_base will point to the start
2345  * of the copied in the code segment, and *code_end will point after the end of 
2346  * the copied code.
2347  */
2348 void
2349 nacl_domain_code_validate (MonoDomain *domain, guint8 **buf_base, int buf_size, guint8 **code_end)
2350 {
2351         guint8 *tmp = nacl_domain_get_code_dest (domain, *buf_base);
2352         mono_domain_code_commit (domain, *buf_base, buf_size, *code_end - *buf_base);
2353         *code_end = tmp + (*code_end - *buf_base);
2354         *buf_base = tmp;
2355 }
2356
2357 #else
2358
2359 /* no-op versions of Native Client functions */
2360
2361 void *
2362 nacl_domain_get_code_dest (MonoDomain *domain, void *data)
2363 {
2364         return data;
2365 }
2366
2367 void
2368 nacl_domain_code_validate (MonoDomain *domain, guint8 **buf_base, int buf_size, guint8 **code_end)
2369 {
2370 }
2371
2372 #endif
2373
2374 /*
2375  * mono_domain_code_foreach:
2376  * Iterate over the code thunks of the code manager of @domain.
2377  * 
2378  * The @func callback MUST not take any locks. If it really needs to, it must respect
2379  * the locking rules of the runtime: http://www.mono-project.com/Mono:Runtime:Documentation:ThreadSafety 
2380  * LOCKING: Acquires the domain lock.
2381  */
2382
2383 void
2384 mono_domain_code_foreach (MonoDomain *domain, MonoCodeManagerFunc func, void *user_data)
2385 {
2386         mono_domain_lock (domain);
2387         mono_code_manager_foreach (domain->code_mp, func, user_data);
2388         mono_domain_unlock (domain);
2389 }
2390
2391
2392 void 
2393 mono_context_set (MonoAppContext * new_context)
2394 {
2395         SET_APPCONTEXT (new_context);
2396 }
2397
2398 MonoAppContext * 
2399 mono_context_get (void)
2400 {
2401         return GET_APPCONTEXT ();
2402 }
2403
2404 /* LOCKING: the caller holds the lock for this domain */
2405 void
2406 mono_domain_add_class_static_data (MonoDomain *domain, MonoClass *klass, gpointer data, guint32 *bitmap)
2407 {
2408         /* The first entry in the array is the index of the next free slot
2409          * and the total size of the array
2410          */
2411         int next;
2412         if (domain->static_data_array) {
2413                 int size = GPOINTER_TO_INT (domain->static_data_array [1]);
2414                 next = GPOINTER_TO_INT (domain->static_data_array [0]);
2415                 if (next >= size) {
2416                         /* 'data' is allocated by alloc_fixed */
2417                         gpointer *new_array = mono_gc_alloc_fixed (sizeof (gpointer) * (size * 2), MONO_GC_ROOT_DESCR_FOR_FIXED (size * 2));
2418                         mono_gc_memmove_aligned (new_array, domain->static_data_array, sizeof (gpointer) * size);
2419                         size *= 2;
2420                         new_array [1] = GINT_TO_POINTER (size);
2421                         mono_gc_free_fixed (domain->static_data_array);
2422                         domain->static_data_array = new_array;
2423                 }
2424         } else {
2425                 int size = 32;
2426                 gpointer *new_array = mono_gc_alloc_fixed (sizeof (gpointer) * size, MONO_GC_ROOT_DESCR_FOR_FIXED (size));
2427                 next = 2;
2428                 new_array [0] = GINT_TO_POINTER (next);
2429                 new_array [1] = GINT_TO_POINTER (size);
2430                 domain->static_data_array = new_array;
2431         }
2432         domain->static_data_array [next++] = data;
2433         domain->static_data_array [0] = GINT_TO_POINTER (next);
2434 }
2435
2436 MonoImage*
2437 mono_get_corlib (void)
2438 {
2439         return mono_defaults.corlib;
2440 }
2441
2442 MonoClass*
2443 mono_get_object_class (void)
2444 {
2445         return mono_defaults.object_class;
2446 }
2447
2448 MonoClass*
2449 mono_get_byte_class (void)
2450 {
2451         return mono_defaults.byte_class;
2452 }
2453
2454 MonoClass*
2455 mono_get_void_class (void)
2456 {
2457         return mono_defaults.void_class;
2458 }
2459
2460 MonoClass*
2461 mono_get_boolean_class (void)
2462 {
2463         return mono_defaults.boolean_class;
2464 }
2465
2466 MonoClass*
2467 mono_get_sbyte_class (void)
2468 {
2469         return mono_defaults.sbyte_class;
2470 }
2471
2472 MonoClass*
2473 mono_get_int16_class (void)
2474 {
2475         return mono_defaults.int16_class;
2476 }
2477
2478 MonoClass*
2479 mono_get_uint16_class (void)
2480 {
2481         return mono_defaults.uint16_class;
2482 }
2483
2484 MonoClass*
2485 mono_get_int32_class (void)
2486 {
2487         return mono_defaults.int32_class;
2488 }
2489
2490 MonoClass*
2491 mono_get_uint32_class (void)
2492 {
2493         return mono_defaults.uint32_class;
2494 }
2495
2496 MonoClass*
2497 mono_get_intptr_class (void)
2498 {
2499         return mono_defaults.int_class;
2500 }
2501
2502 MonoClass*
2503 mono_get_uintptr_class (void)
2504 {
2505         return mono_defaults.uint_class;
2506 }
2507
2508 MonoClass*
2509 mono_get_int64_class (void)
2510 {
2511         return mono_defaults.int64_class;
2512 }
2513
2514 MonoClass*
2515 mono_get_uint64_class (void)
2516 {
2517         return mono_defaults.uint64_class;
2518 }
2519
2520 MonoClass*
2521 mono_get_single_class (void)
2522 {
2523         return mono_defaults.single_class;
2524 }
2525
2526 MonoClass*
2527 mono_get_double_class (void)
2528 {
2529         return mono_defaults.double_class;
2530 }
2531
2532 MonoClass*
2533 mono_get_char_class (void)
2534 {
2535         return mono_defaults.char_class;
2536 }
2537
2538 MonoClass*
2539 mono_get_string_class (void)
2540 {
2541         return mono_defaults.string_class;
2542 }
2543
2544 MonoClass*
2545 mono_get_enum_class (void)
2546 {
2547         return mono_defaults.enum_class;
2548 }
2549
2550 MonoClass*
2551 mono_get_array_class (void)
2552 {
2553         return mono_defaults.array_class;
2554 }
2555
2556 MonoClass*
2557 mono_get_thread_class (void)
2558 {
2559         return mono_defaults.thread_class;
2560 }
2561
2562 MonoClass*
2563 mono_get_exception_class (void)
2564 {
2565         return mono_defaults.exception_class;
2566 }
2567
2568
2569 static char* get_attribute_value (const gchar **attribute_names, 
2570                                         const gchar **attribute_values, 
2571                                         const char *att_name)
2572 {
2573         int n;
2574         for (n=0; attribute_names[n] != NULL; n++) {
2575                 if (strcmp (attribute_names[n], att_name) == 0)
2576                         return g_strdup (attribute_values[n]);
2577         }
2578         return NULL;
2579 }
2580
2581 static void start_element (GMarkupParseContext *context, 
2582                            const gchar         *element_name,
2583                            const gchar        **attribute_names,
2584                            const gchar        **attribute_values,
2585                            gpointer             user_data,
2586                            GError             **error)
2587 {
2588         AppConfigInfo* app_config = (AppConfigInfo*) user_data;
2589         
2590         if (strcmp (element_name, "configuration") == 0) {
2591                 app_config->configuration_count++;
2592                 return;
2593         }
2594         if (strcmp (element_name, "startup") == 0) {
2595                 app_config->startup_count++;
2596                 return;
2597         }
2598         
2599         if (app_config->configuration_count != 1 || app_config->startup_count != 1)
2600                 return;
2601         
2602         if (strcmp (element_name, "requiredRuntime") == 0) {
2603                 app_config->required_runtime = get_attribute_value (attribute_names, attribute_values, "version");
2604         } else if (strcmp (element_name, "supportedRuntime") == 0) {
2605                 char *version = get_attribute_value (attribute_names, attribute_values, "version");
2606                 app_config->supported_runtimes = g_slist_append (app_config->supported_runtimes, version);
2607         }
2608 }
2609
2610 static void end_element   (GMarkupParseContext *context,
2611                            const gchar         *element_name,
2612                            gpointer             user_data,
2613                            GError             **error)
2614 {
2615         AppConfigInfo* app_config = (AppConfigInfo*) user_data;
2616         
2617         if (strcmp (element_name, "configuration") == 0) {
2618                 app_config->configuration_count--;
2619         } else if (strcmp (element_name, "startup") == 0) {
2620                 app_config->startup_count--;
2621         }
2622 }
2623
2624 static const GMarkupParser 
2625 mono_parser = {
2626         start_element,
2627         end_element,
2628         NULL,
2629         NULL,
2630         NULL
2631 };
2632
2633 static AppConfigInfo *
2634 app_config_parse (const char *exe_filename)
2635 {
2636         AppConfigInfo *app_config;
2637         GMarkupParseContext *context;
2638         char *text;
2639         gsize len;
2640         const char *bundled_config;
2641         char *config_filename;
2642
2643         bundled_config = mono_config_string_for_assembly_file (exe_filename);
2644
2645         if (bundled_config) {
2646                 text = g_strdup (bundled_config);
2647                 len = strlen (text);
2648         } else {
2649                 config_filename = g_strconcat (exe_filename, ".config", NULL);
2650
2651                 if (!g_file_get_contents (config_filename, &text, &len, NULL)) {
2652                         g_free (config_filename);
2653                         return NULL;
2654                 }
2655                 g_free (config_filename);
2656         }
2657
2658         app_config = g_new0 (AppConfigInfo, 1);
2659
2660         context = g_markup_parse_context_new (&mono_parser, 0, app_config, NULL);
2661         if (g_markup_parse_context_parse (context, text, len, NULL)) {
2662                 g_markup_parse_context_end_parse (context, NULL);
2663         }
2664         g_markup_parse_context_free (context);
2665         g_free (text);
2666         return app_config;
2667 }
2668
2669 static void 
2670 app_config_free (AppConfigInfo* app_config)
2671 {
2672         char *rt;
2673         GSList *list = app_config->supported_runtimes;
2674         while (list != NULL) {
2675                 rt = (char*)list->data;
2676                 g_free (rt);
2677                 list = g_slist_next (list);
2678         }
2679         g_slist_free (app_config->supported_runtimes);
2680         g_free (app_config->required_runtime);
2681         g_free (app_config);
2682 }
2683
2684
2685 static const MonoRuntimeInfo*
2686 get_runtime_by_version (const char *version)
2687 {
2688         int n;
2689         int max = G_N_ELEMENTS (supported_runtimes);
2690         int vlen;
2691
2692         if (!version)
2693                 return NULL;
2694
2695         for (n=0; n<max; n++) {
2696                 if (strcmp (version, supported_runtimes[n].runtime_version) == 0)
2697                         return &supported_runtimes[n];
2698         }
2699         
2700         vlen = strlen (version);
2701         if (vlen >= 4 && version [1] - '0' >= 4) {
2702                 for (n=0; n<max; n++) {
2703                         if (strncmp (version, supported_runtimes[n].runtime_version, 4) == 0)
2704                                 return &supported_runtimes[n];
2705                 }
2706         }
2707         
2708         return NULL;
2709 }
2710
2711 static void
2712 get_runtimes_from_exe (const char *exe_file, MonoImage **exe_image, const MonoRuntimeInfo** runtimes)
2713 {
2714         AppConfigInfo* app_config;
2715         char *version;
2716         const MonoRuntimeInfo* runtime = NULL;
2717         MonoImage *image = NULL;
2718         
2719         app_config = app_config_parse (exe_file);
2720         
2721         if (app_config != NULL) {
2722                 /* Check supportedRuntime elements, if none is supported, fail.
2723                  * If there are no such elements, look for a requiredRuntime element.
2724                  */
2725                 if (app_config->supported_runtimes != NULL) {
2726                         int n = 0;
2727                         GSList *list = app_config->supported_runtimes;
2728                         while (list != NULL) {
2729                                 version = (char*) list->data;
2730                                 runtime = get_runtime_by_version (version);
2731                                 if (runtime != NULL)
2732                                         runtimes [n++] = runtime;
2733                                 list = g_slist_next (list);
2734                         }
2735                         runtimes [n] = NULL;
2736                         app_config_free (app_config);
2737                         return;
2738                 }
2739                 
2740                 /* Check the requiredRuntime element. This is for 1.0 apps only. */
2741                 if (app_config->required_runtime != NULL) {
2742                         runtimes [0] = get_runtime_by_version (app_config->required_runtime);
2743                         runtimes [1] = NULL;
2744                         app_config_free (app_config);
2745                         return;
2746                 }
2747                 app_config_free (app_config);
2748         }
2749         
2750         /* Look for a runtime with the exact version */
2751         image = mono_assembly_open_from_bundle (exe_file, NULL, FALSE);
2752
2753         if (image == NULL)
2754                 image = mono_image_open (exe_file, NULL);
2755
2756         if (image == NULL) {
2757                 /* The image is wrong or the file was not found. In this case return
2758                  * a default runtime and leave to the initialization method the work of
2759                  * reporting the error.
2760                  */
2761                 runtimes [0] = get_runtime_by_version (DEFAULT_RUNTIME_VERSION);
2762                 runtimes [1] = NULL;
2763                 return;
2764         }
2765
2766         *exe_image = image;
2767
2768         runtimes [0] = get_runtime_by_version (image->version);
2769         runtimes [1] = NULL;
2770 }
2771
2772
2773 /**
2774  * mono_get_runtime_info:
2775  *
2776  * Returns: the version of the current runtime instance.
2777  */
2778 const MonoRuntimeInfo*
2779 mono_get_runtime_info (void)
2780 {
2781         return current_runtime;
2782 }
2783
2784 gchar *
2785 mono_debugger_check_runtime_version (const char *filename)
2786 {
2787         const MonoRuntimeInfo* runtimes [G_N_ELEMENTS (supported_runtimes) + 1];
2788         const MonoRuntimeInfo *rinfo;
2789         MonoImage *image;
2790
2791         get_runtimes_from_exe (filename, &image, runtimes);
2792         rinfo = runtimes [0];
2793
2794         if (!rinfo)
2795                 return g_strdup_printf ("Cannot get runtime version from assembly `%s'", filename);
2796
2797         if (rinfo != current_runtime)
2798                 return g_strdup_printf ("The Mono Debugger is currently using the `%s' runtime, but "
2799                                         "the assembly `%s' requires version `%s'", current_runtime->runtime_version,
2800                                         filename, rinfo->runtime_version);
2801
2802         return NULL;
2803 }
2804
2805 /**
2806  * mono_framework_version:
2807  *
2808  * Return the major version of the framework curently executing.
2809  */
2810 int
2811 mono_framework_version (void)
2812 {
2813         return current_runtime->framework_version [0] - '0';
2814 }
2815
2816 void
2817 mono_enable_debug_domain_unload (gboolean enable)
2818 {
2819         debug_domain_unload = enable;
2820 }
2821
2822 MonoAotCacheConfig *
2823 mono_get_aot_cache_config (void)
2824 {
2825         return &aot_cache_config;
2826 }