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