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