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