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