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