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