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