Merge mono/io-layer, mono/metadata, mono/arch/x86 and configure.in for Native Client
[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
1275         mono_load_coree (exe_filename);
1276 #endif
1277
1278         mono_perfcounters_init ();
1279
1280         mono_counters_register ("Max native code in a domain", MONO_COUNTER_INT|MONO_COUNTER_JIT, &max_domain_code_size);
1281         mono_counters_register ("Max code space allocated in a domain", MONO_COUNTER_INT|MONO_COUNTER_JIT, &max_domain_code_alloc);
1282         mono_counters_register ("Total code space allocated", MONO_COUNTER_INT|MONO_COUNTER_JIT, &total_domain_code_alloc);
1283
1284         mono_gc_base_init ();
1285
1286         appdomain_thread_id = TlsAlloc ();
1287
1288         InitializeCriticalSection (&appdomains_mutex);
1289
1290         mono_metadata_init ();
1291         mono_images_init ();
1292         mono_assemblies_init ();
1293         mono_classes_init ();
1294         mono_loader_init ();
1295         mono_reflection_init ();
1296
1297         /* FIXME: When should we release this memory? */
1298         MONO_GC_REGISTER_ROOT_FIXED (appdomains_list);
1299
1300         domain = mono_domain_create ();
1301         mono_root_domain = domain;
1302
1303         SET_APPDOMAIN (domain);
1304         
1305         /* Get a list of runtimes supported by the exe */
1306         if (exe_filename != NULL) {
1307                 /*
1308                  * This function will load the exe file as a MonoImage. We need to close it, but
1309                  * that would mean it would be reloaded later. So instead, we save it to
1310                  * exe_image, and close it during shutdown.
1311                  */
1312                 get_runtimes_from_exe (exe_filename, &exe_image, runtimes);
1313 #ifdef HOST_WIN32
1314                 if (!exe_image) {
1315                         exe_image = mono_assembly_open_from_bundle (exe_filename, NULL, FALSE);
1316                         if (!exe_image)
1317                                 exe_image = mono_image_open (exe_filename, NULL);
1318                 }
1319                 mono_fixup_exe_image (exe_image);
1320 #endif
1321         } else if (runtime_version != NULL) {
1322                 runtimes [0] = get_runtime_by_version (runtime_version);
1323                 runtimes [1] = NULL;
1324         }
1325
1326         if (runtimes [0] == NULL) {
1327                 const MonoRuntimeInfo *default_runtime = get_runtime_by_version (DEFAULT_RUNTIME_VERSION);
1328                 runtimes [0] = default_runtime;
1329                 runtimes [1] = NULL;
1330                 g_print ("WARNING: The runtime version supported by this application is unavailable.\n");
1331                 g_print ("Using default runtime: %s\n", default_runtime->runtime_version); 
1332         }
1333
1334         /* The selected runtime will be the first one for which there is a mscrolib.dll */
1335         for (n = 0; runtimes [n] != NULL && ass == NULL; n++) {
1336                 current_runtime = runtimes [n];
1337                 ass = mono_assembly_load_corlib (current_runtime, &status);
1338                 if (status != MONO_IMAGE_OK && status != MONO_IMAGE_ERROR_ERRNO)
1339                         break;
1340
1341         }
1342         
1343         if ((status != MONO_IMAGE_OK) || (ass == NULL)) {
1344                 switch (status){
1345                 case MONO_IMAGE_ERROR_ERRNO: {
1346                         char *corlib_file = g_build_filename (mono_assembly_getrootdir (), "mono", current_runtime->framework_version, "mscorlib.dll", NULL);
1347                         g_print ("The assembly mscorlib.dll was not found or could not be loaded.\n");
1348                         g_print ("It should have been installed in the `%s' directory.\n", corlib_file);
1349                         g_free (corlib_file);
1350                         break;
1351                 }
1352                 case MONO_IMAGE_IMAGE_INVALID:
1353                         g_print ("The file %s/mscorlib.dll is an invalid CIL image\n",
1354                                  mono_assembly_getrootdir ());
1355                         break;
1356                 case MONO_IMAGE_MISSING_ASSEMBLYREF:
1357                         g_print ("Missing assembly reference in %s/mscorlib.dll\n",
1358                                  mono_assembly_getrootdir ());
1359                         break;
1360                 case MONO_IMAGE_OK:
1361                         /* to suppress compiler warning */
1362                         break;
1363                 }
1364                 
1365                 exit (1);
1366         }
1367         mono_defaults.corlib = mono_assembly_get_image (ass);
1368
1369         mono_defaults.object_class = mono_class_from_name (
1370                 mono_defaults.corlib, "System", "Object");
1371         g_assert (mono_defaults.object_class != 0);
1372
1373         mono_defaults.void_class = mono_class_from_name (
1374                 mono_defaults.corlib, "System", "Void");
1375         g_assert (mono_defaults.void_class != 0);
1376
1377         mono_defaults.boolean_class = mono_class_from_name (
1378                 mono_defaults.corlib, "System", "Boolean");
1379         g_assert (mono_defaults.boolean_class != 0);
1380
1381         mono_defaults.byte_class = mono_class_from_name (
1382                 mono_defaults.corlib, "System", "Byte");
1383         g_assert (mono_defaults.byte_class != 0);
1384
1385         mono_defaults.sbyte_class = mono_class_from_name (
1386                 mono_defaults.corlib, "System", "SByte");
1387         g_assert (mono_defaults.sbyte_class != 0);
1388
1389         mono_defaults.int16_class = mono_class_from_name (
1390                 mono_defaults.corlib, "System", "Int16");
1391         g_assert (mono_defaults.int16_class != 0);
1392
1393         mono_defaults.uint16_class = mono_class_from_name (
1394                 mono_defaults.corlib, "System", "UInt16");
1395         g_assert (mono_defaults.uint16_class != 0);
1396
1397         mono_defaults.int32_class = mono_class_from_name (
1398                 mono_defaults.corlib, "System", "Int32");
1399         g_assert (mono_defaults.int32_class != 0);
1400
1401         mono_defaults.uint32_class = mono_class_from_name (
1402                 mono_defaults.corlib, "System", "UInt32");
1403         g_assert (mono_defaults.uint32_class != 0);
1404
1405         mono_defaults.uint_class = mono_class_from_name (
1406                 mono_defaults.corlib, "System", "UIntPtr");
1407         g_assert (mono_defaults.uint_class != 0);
1408
1409         mono_defaults.int_class = mono_class_from_name (
1410                 mono_defaults.corlib, "System", "IntPtr");
1411         g_assert (mono_defaults.int_class != 0);
1412
1413         mono_defaults.int64_class = mono_class_from_name (
1414                 mono_defaults.corlib, "System", "Int64");
1415         g_assert (mono_defaults.int64_class != 0);
1416
1417         mono_defaults.uint64_class = mono_class_from_name (
1418                 mono_defaults.corlib, "System", "UInt64");
1419         g_assert (mono_defaults.uint64_class != 0);
1420
1421         mono_defaults.single_class = mono_class_from_name (
1422                 mono_defaults.corlib, "System", "Single");
1423         g_assert (mono_defaults.single_class != 0);
1424
1425         mono_defaults.double_class = mono_class_from_name (
1426                 mono_defaults.corlib, "System", "Double");
1427         g_assert (mono_defaults.double_class != 0);
1428
1429         mono_defaults.char_class = mono_class_from_name (
1430                 mono_defaults.corlib, "System", "Char");
1431         g_assert (mono_defaults.char_class != 0);
1432
1433         mono_defaults.string_class = mono_class_from_name (
1434                 mono_defaults.corlib, "System", "String");
1435         g_assert (mono_defaults.string_class != 0);
1436
1437         mono_defaults.enum_class = mono_class_from_name (
1438                 mono_defaults.corlib, "System", "Enum");
1439         g_assert (mono_defaults.enum_class != 0);
1440
1441         mono_defaults.array_class = mono_class_from_name (
1442                 mono_defaults.corlib, "System", "Array");
1443         g_assert (mono_defaults.array_class != 0);
1444
1445         mono_defaults.delegate_class = mono_class_from_name (
1446                 mono_defaults.corlib, "System", "Delegate");
1447         g_assert (mono_defaults.delegate_class != 0 );
1448
1449         mono_defaults.multicastdelegate_class = mono_class_from_name (
1450                 mono_defaults.corlib, "System", "MulticastDelegate");
1451         g_assert (mono_defaults.multicastdelegate_class != 0 );
1452
1453         mono_defaults.asyncresult_class = mono_class_from_name (
1454                 mono_defaults.corlib, "System.Runtime.Remoting.Messaging", 
1455                 "AsyncResult");
1456         g_assert (mono_defaults.asyncresult_class != 0 );
1457
1458         mono_defaults.manualresetevent_class = mono_class_from_name (
1459                 mono_defaults.corlib, "System.Threading", "ManualResetEvent");
1460         g_assert (mono_defaults.manualresetevent_class != 0 );
1461
1462         mono_defaults.typehandle_class = mono_class_from_name (
1463                 mono_defaults.corlib, "System", "RuntimeTypeHandle");
1464         g_assert (mono_defaults.typehandle_class != 0);
1465
1466         mono_defaults.methodhandle_class = mono_class_from_name (
1467                 mono_defaults.corlib, "System", "RuntimeMethodHandle");
1468         g_assert (mono_defaults.methodhandle_class != 0);
1469
1470         mono_defaults.fieldhandle_class = mono_class_from_name (
1471                 mono_defaults.corlib, "System", "RuntimeFieldHandle");
1472         g_assert (mono_defaults.fieldhandle_class != 0);
1473
1474         mono_defaults.systemtype_class = mono_class_from_name (
1475                 mono_defaults.corlib, "System", "Type");
1476         g_assert (mono_defaults.systemtype_class != 0);
1477
1478         mono_defaults.monotype_class = mono_class_from_name (
1479                 mono_defaults.corlib, "System", "MonoType");
1480         g_assert (mono_defaults.monotype_class != 0);
1481
1482         mono_defaults.exception_class = mono_class_from_name (
1483                 mono_defaults.corlib, "System", "Exception");
1484         g_assert (mono_defaults.exception_class != 0);
1485
1486         mono_defaults.threadabortexception_class = mono_class_from_name (
1487                 mono_defaults.corlib, "System.Threading", "ThreadAbortException");
1488         g_assert (mono_defaults.threadabortexception_class != 0);
1489
1490         mono_defaults.thread_class = mono_class_from_name (
1491                 mono_defaults.corlib, "System.Threading", "Thread");
1492         g_assert (mono_defaults.thread_class != 0);
1493
1494         mono_defaults.internal_thread_class = mono_class_from_name (
1495                 mono_defaults.corlib, "System.Threading", "InternalThread");
1496         if (!mono_defaults.internal_thread_class) {
1497                 /* This can happen with an old mscorlib */
1498                 fprintf (stderr, "Corlib too old for this runtime.\n");
1499                 fprintf (stderr, "Loaded from: %s\n",
1500                                  mono_defaults.corlib? mono_image_get_filename (mono_defaults.corlib): "unknown");
1501                 exit (1);
1502         }
1503
1504         mono_defaults.appdomain_class = mono_class_from_name (
1505                 mono_defaults.corlib, "System", "AppDomain");
1506         g_assert (mono_defaults.appdomain_class != 0);
1507
1508         mono_defaults.transparent_proxy_class = mono_class_from_name (
1509                 mono_defaults.corlib, "System.Runtime.Remoting.Proxies", "TransparentProxy");
1510         g_assert (mono_defaults.transparent_proxy_class != 0);
1511
1512         mono_defaults.real_proxy_class = mono_class_from_name (
1513                 mono_defaults.corlib, "System.Runtime.Remoting.Proxies", "RealProxy");
1514         g_assert (mono_defaults.real_proxy_class != 0);
1515
1516         mono_defaults.mono_method_message_class = mono_class_from_name (
1517                 mono_defaults.corlib, "System.Runtime.Remoting.Messaging", "MonoMethodMessage");
1518         g_assert (mono_defaults.mono_method_message_class != 0);
1519
1520         mono_defaults.field_info_class = mono_class_from_name (
1521                 mono_defaults.corlib, "System.Reflection", "FieldInfo");
1522         g_assert (mono_defaults.field_info_class != 0);
1523
1524         mono_defaults.method_info_class = mono_class_from_name (
1525                 mono_defaults.corlib, "System.Reflection", "MethodInfo");
1526         g_assert (mono_defaults.method_info_class != 0);
1527
1528         mono_defaults.stringbuilder_class = mono_class_from_name (
1529                 mono_defaults.corlib, "System.Text", "StringBuilder");
1530         g_assert (mono_defaults.stringbuilder_class != 0);
1531
1532         mono_defaults.math_class = mono_class_from_name (
1533                 mono_defaults.corlib, "System", "Math");
1534         g_assert (mono_defaults.math_class != 0);
1535
1536         mono_defaults.stack_frame_class = mono_class_from_name (
1537                 mono_defaults.corlib, "System.Diagnostics", "StackFrame");
1538         g_assert (mono_defaults.stack_frame_class != 0);
1539
1540         mono_defaults.stack_trace_class = mono_class_from_name (
1541                 mono_defaults.corlib, "System.Diagnostics", "StackTrace");
1542         g_assert (mono_defaults.stack_trace_class != 0);
1543
1544         mono_defaults.marshal_class = mono_class_from_name (
1545                 mono_defaults.corlib, "System.Runtime.InteropServices", "Marshal");
1546         g_assert (mono_defaults.marshal_class != 0);
1547
1548         mono_defaults.iserializeable_class = mono_class_from_name (
1549                 mono_defaults.corlib, "System.Runtime.Serialization", "ISerializable");
1550         g_assert (mono_defaults.iserializeable_class != 0);
1551
1552         mono_defaults.serializationinfo_class = mono_class_from_name (
1553                 mono_defaults.corlib, "System.Runtime.Serialization", "SerializationInfo");
1554         g_assert (mono_defaults.serializationinfo_class != 0);
1555
1556         mono_defaults.streamingcontext_class = mono_class_from_name (
1557                 mono_defaults.corlib, "System.Runtime.Serialization", "StreamingContext");
1558         g_assert (mono_defaults.streamingcontext_class != 0);
1559
1560         mono_defaults.typed_reference_class =  mono_class_from_name (
1561                 mono_defaults.corlib, "System", "TypedReference");
1562         g_assert (mono_defaults.typed_reference_class != 0);
1563
1564         mono_defaults.argumenthandle_class =  mono_class_from_name (
1565                 mono_defaults.corlib, "System", "RuntimeArgumentHandle");
1566         g_assert (mono_defaults.argumenthandle_class != 0);
1567
1568         mono_defaults.marshalbyrefobject_class =  mono_class_from_name (
1569                 mono_defaults.corlib, "System", "MarshalByRefObject");
1570         g_assert (mono_defaults.marshalbyrefobject_class != 0);
1571
1572         mono_defaults.monitor_class =  mono_class_from_name (
1573                 mono_defaults.corlib, "System.Threading", "Monitor");
1574         g_assert (mono_defaults.monitor_class != 0);
1575
1576         mono_defaults.iremotingtypeinfo_class = mono_class_from_name (
1577                 mono_defaults.corlib, "System.Runtime.Remoting", "IRemotingTypeInfo");
1578         g_assert (mono_defaults.iremotingtypeinfo_class != 0);
1579
1580         mono_defaults.runtimesecurityframe_class = mono_class_from_name (
1581                 mono_defaults.corlib, "System.Security", "RuntimeSecurityFrame");
1582
1583         mono_defaults.executioncontext_class = mono_class_from_name (
1584                 mono_defaults.corlib, "System.Threading", "ExecutionContext");
1585
1586         mono_defaults.internals_visible_class = mono_class_from_name (
1587                 mono_defaults.corlib, "System.Runtime.CompilerServices", "InternalsVisibleToAttribute");
1588
1589         mono_defaults.critical_finalizer_object = mono_class_from_name (
1590                 mono_defaults.corlib, "System.Runtime.ConstrainedExecution", "CriticalFinalizerObject");
1591
1592         /*
1593          * mscorlib needs a little help, only now it can load its friends list (after we have
1594          * loaded the InternalsVisibleToAttribute), load it now
1595          */
1596         mono_assembly_load_friends (ass);
1597         
1598         mono_defaults.safehandle_class = mono_class_from_name (
1599                 mono_defaults.corlib, "System.Runtime.InteropServices", "SafeHandle");
1600
1601         mono_defaults.handleref_class = mono_class_from_name (
1602                 mono_defaults.corlib, "System.Runtime.InteropServices", "HandleRef");
1603
1604         mono_defaults.attribute_class = mono_class_from_name (
1605                 mono_defaults.corlib, "System", "Attribute");
1606
1607         mono_defaults.customattribute_data_class = mono_class_from_name (
1608                 mono_defaults.corlib, "System.Reflection", "CustomAttributeData");
1609
1610         /* these are initialized lazily when COM features are used */
1611         mono_defaults.variant_class = NULL;
1612         mono_defaults.com_object_class = NULL;
1613         mono_defaults.com_interop_proxy_class = NULL;
1614         mono_defaults.iunknown_class = NULL;
1615         mono_defaults.idispatch_class = NULL;
1616
1617         /*
1618          * Note that mono_defaults.generic_*_class is only non-NULL if we're
1619          * using the 2.0 corlib.
1620          */
1621         mono_class_init (mono_defaults.array_class);
1622         mono_defaults.generic_nullable_class = mono_class_from_name (
1623                 mono_defaults.corlib, "System", "Nullable`1");
1624         mono_defaults.generic_ilist_class = mono_class_from_name (
1625                 mono_defaults.corlib, "System.Collections.Generic", "IList`1");
1626
1627         domain->friendly_name = g_path_get_basename (filename);
1628
1629         _mono_debug_init_corlib (domain);
1630
1631         return domain;
1632 }
1633
1634 /**
1635  * mono_init:
1636  * 
1637  * Creates the initial application domain and initializes the mono_defaults
1638  * structure.
1639  * This function is guaranteed to not run any IL code.
1640  * The runtime is initialized using the default runtime version.
1641  *
1642  * Returns: the initial domain.
1643  */
1644 MonoDomain *
1645 mono_init (const char *domain_name)
1646 {
1647         return mono_init_internal (domain_name, NULL, DEFAULT_RUNTIME_VERSION);
1648 }
1649
1650 /**
1651  * mono_init_from_assembly:
1652  * @domain_name: name to give to the initial domain
1653  * @filename: filename to load on startup
1654  *
1655  * Used by the runtime, users should use mono_jit_init instead.
1656  *
1657  * Creates the initial application domain and initializes the mono_defaults
1658  * structure.
1659  * This function is guaranteed to not run any IL code.
1660  * The runtime is initialized using the runtime version required by the
1661  * provided executable. The version is determined by looking at the exe 
1662  * configuration file and the version PE field)
1663  *
1664  * Returns: the initial domain.
1665  */
1666 MonoDomain *
1667 mono_init_from_assembly (const char *domain_name, const char *filename)
1668 {
1669         return mono_init_internal (domain_name, filename, NULL);
1670 }
1671
1672 /**
1673  * mono_init_version:
1674  * 
1675  * Used by the runtime, users should use mono_jit_init instead.
1676  * 
1677  * Creates the initial application domain and initializes the mono_defaults
1678  * structure.
1679  *
1680  * This function is guaranteed to not run any IL code.
1681  * The runtime is initialized using the provided rutime version.
1682  *
1683  * Returns: the initial domain.
1684  */
1685 MonoDomain *
1686 mono_init_version (const char *domain_name, const char *version)
1687 {
1688         return mono_init_internal (domain_name, NULL, version);
1689 }
1690
1691 /**
1692  * mono_init_com_types:
1693  *
1694  * Initializes all types needed for COM Interop in mono_defaults structure. 
1695  */
1696 void 
1697 mono_init_com_types (void)
1698 {
1699         static gboolean initialized = FALSE;
1700
1701         if (initialized)
1702                 return;
1703         
1704         /* FIXME: do I need some threading protection here */
1705
1706         g_assert (mono_defaults.corlib);
1707
1708         mono_defaults.variant_class = mono_class_from_name (
1709                 mono_defaults.corlib, "System", "Variant");
1710         g_assert (mono_defaults.variant_class != 0);
1711
1712         mono_defaults.com_object_class = mono_class_from_name (
1713                 mono_defaults.corlib, "System", "__ComObject");
1714         g_assert (mono_defaults.com_object_class != 0);
1715
1716         mono_defaults.com_interop_proxy_class = mono_class_from_name (
1717                 mono_defaults.corlib, "Mono.Interop", "ComInteropProxy");
1718         g_assert (mono_defaults.com_interop_proxy_class != 0);
1719
1720         mono_defaults.iunknown_class = mono_class_from_name (
1721                 mono_defaults.corlib, "Mono.Interop", "IUnknown");
1722         g_assert (mono_defaults.iunknown_class != 0);
1723
1724         mono_defaults.idispatch_class = mono_class_from_name (
1725                 mono_defaults.corlib, "Mono.Interop", "IDispatch");
1726         g_assert (mono_defaults.idispatch_class != 0);
1727
1728         initialized = TRUE;
1729 }
1730
1731 /**
1732  * mono_cleanup:
1733  *
1734  * Cleans up all metadata modules. 
1735  */
1736 void
1737 mono_cleanup (void)
1738 {
1739         mono_close_exe_image ();
1740
1741         mono_defaults.corlib = NULL;
1742
1743         mono_config_cleanup ();
1744         mono_loader_cleanup ();
1745         mono_classes_cleanup ();
1746         mono_assemblies_cleanup ();
1747         mono_images_cleanup ();
1748         mono_debug_cleanup ();
1749         mono_metadata_cleanup ();
1750
1751         TlsFree (appdomain_thread_id);
1752         DeleteCriticalSection (&appdomains_mutex);
1753
1754         /*
1755          * This should be called last as TlsGetValue ()/TlsSetValue () can be called during
1756          * shutdown.
1757          */
1758 #ifndef HOST_WIN32
1759         _wapi_cleanup ();
1760 #endif
1761 }
1762
1763 void
1764 mono_close_exe_image (void)
1765 {
1766         if (exe_image)
1767                 mono_image_close (exe_image);
1768 }
1769
1770 /**
1771  * mono_get_root_domain:
1772  *
1773  * The root AppDomain is the initial domain created by the runtime when it is
1774  * initialized.  Programs execute on this AppDomain, but can create new ones
1775  * later.   Currently there is no unmanaged API to create new AppDomains, this
1776  * must be done from managed code.
1777  *
1778  * Returns: the root appdomain, to obtain the current domain, use mono_domain_get ()
1779  */
1780 MonoDomain*
1781 mono_get_root_domain (void)
1782 {
1783         return mono_root_domain;
1784 }
1785
1786 /**
1787  * mono_domain_get:
1788  *
1789  * Returns: the current domain, to obtain the root domain use
1790  * mono_get_root_domain().
1791  */
1792 MonoDomain *
1793 mono_domain_get ()
1794 {
1795         return GET_APPDOMAIN ();
1796 }
1797
1798 void
1799 mono_domain_unset (void)
1800 {
1801         SET_APPDOMAIN (NULL);
1802 }
1803
1804 void
1805 mono_domain_set_internal_with_options (MonoDomain *domain, gboolean migrate_exception)
1806 {
1807         MonoInternalThread *thread;
1808
1809         if (mono_domain_get () == domain)
1810                 return;
1811
1812         SET_APPDOMAIN (domain);
1813         SET_APPCONTEXT (domain->default_context);
1814
1815         if (migrate_exception) {
1816                 thread = mono_thread_internal_current ();
1817                 if (!thread->abort_exc)
1818                         return;
1819
1820                 g_assert (thread->abort_exc->object.vtable->domain != domain);
1821                 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
1822                 g_assert (thread->abort_exc->object.vtable->domain == domain);
1823         }
1824 }
1825
1826 /**
1827  * mono_domain_set_internal:
1828  * @domain: the new domain
1829  *
1830  * Sets the current domain to @domain.
1831  */
1832 void
1833 mono_domain_set_internal (MonoDomain *domain)
1834 {
1835         mono_domain_set_internal_with_options (domain, TRUE);
1836 }
1837
1838 void
1839 mono_domain_foreach (MonoDomainFunc func, gpointer user_data)
1840 {
1841         int i, size;
1842         MonoDomain **copy;
1843
1844         /*
1845          * Create a copy of the data to avoid calling the user callback
1846          * inside the lock because that could lead to deadlocks.
1847          * We can do this because this function is not perf. critical.
1848          */
1849         mono_appdomains_lock ();
1850         size = appdomain_list_size;
1851         copy = mono_gc_alloc_fixed (appdomain_list_size * sizeof (void*), NULL);
1852         memcpy (copy, appdomains_list, appdomain_list_size * sizeof (void*));
1853         mono_appdomains_unlock ();
1854
1855         for (i = 0; i < size; ++i) {
1856                 if (copy [i])
1857                         func (copy [i], user_data);
1858         }
1859
1860         mono_gc_free_fixed (copy);
1861 }
1862
1863 /**
1864  * mono_domain_assembly_open:
1865  * @domain: the application domain
1866  * @name: file name of the assembly
1867  *
1868  * fixme: maybe we should integrate this with mono_assembly_open ??
1869  */
1870 MonoAssembly *
1871 mono_domain_assembly_open (MonoDomain *domain, const char *name)
1872 {
1873         MonoDomain *current;
1874         MonoAssembly *ass;
1875         GSList *tmp;
1876
1877         mono_domain_assemblies_lock (domain);
1878         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1879                 ass = tmp->data;
1880                 if (strcmp (name, ass->aname.name) == 0) {
1881                         mono_domain_assemblies_unlock (domain);
1882                         return ass;
1883                 }
1884         }
1885         mono_domain_assemblies_unlock (domain);
1886
1887         if (domain != mono_domain_get ()) {
1888                 current = mono_domain_get ();
1889
1890                 mono_domain_set (domain, FALSE);
1891                 ass = mono_assembly_open (name, NULL);
1892                 mono_domain_set (current, FALSE);
1893         } else {
1894                 ass = mono_assembly_open (name, NULL);
1895         }
1896
1897         return ass;
1898 }
1899
1900 static void
1901 free_slist (gpointer key, gpointer value, gpointer user_data)
1902 {
1903         g_slist_free (value);
1904 }
1905
1906 static void
1907 unregister_vtable_reflection_type (MonoVTable *vtable)
1908 {
1909         MonoObject *type = vtable->type;
1910
1911         if (type->vtable->klass != mono_defaults.monotype_class)
1912                 MONO_GC_UNREGISTER_ROOT_IF_MOVING (vtable->type);
1913 }
1914
1915 void
1916 mono_domain_free (MonoDomain *domain, gboolean force)
1917 {
1918         int code_size, code_alloc;
1919         GSList *tmp;
1920         if ((domain == mono_root_domain) && !force) {
1921                 g_warning ("cant unload root domain");
1922                 return;
1923         }
1924
1925         if (mono_dont_free_domains)
1926                 return;
1927
1928         mono_profiler_appdomain_event (domain, MONO_PROFILE_START_UNLOAD);
1929
1930         mono_debug_domain_unload (domain);
1931
1932         mono_appdomains_lock ();
1933         appdomains_list [domain->domain_id] = NULL;
1934         mono_appdomains_unlock ();
1935
1936         /* must do this early as it accesses fields and types */
1937         if (domain->special_static_fields) {
1938                 mono_alloc_special_static_data_free (domain->special_static_fields);
1939                 g_hash_table_destroy (domain->special_static_fields);
1940                 domain->special_static_fields = NULL;
1941         }
1942
1943         /*
1944          * We must destroy all these hash tables here because they
1945          * contain references to managed objects belonging to the
1946          * domain.  Once we let the GC clear the domain there must be
1947          * no more such references, or we'll crash if a collection
1948          * occurs.
1949          */
1950         mono_g_hash_table_destroy (domain->ldstr_table);
1951         domain->ldstr_table = NULL;
1952
1953         mono_g_hash_table_destroy (domain->env);
1954         domain->env = NULL;
1955
1956         mono_reflection_cleanup_domain (domain);
1957
1958         if (domain->type_hash) {
1959                 mono_g_hash_table_destroy (domain->type_hash);
1960                 domain->type_hash = NULL;
1961         }
1962         if (domain->type_init_exception_hash) {
1963                 mono_g_hash_table_destroy (domain->type_init_exception_hash);
1964                 domain->type_init_exception_hash = NULL;
1965         }
1966
1967         if (domain->class_vtable_array) {
1968                 int i;
1969                 for (i = 0; i < domain->class_vtable_array->len; ++i)
1970                         unregister_vtable_reflection_type (g_ptr_array_index (domain->class_vtable_array, i));
1971         }
1972
1973         /* This needs to be done before closing assemblies */
1974         mono_gc_clear_domain (domain);
1975
1976         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1977                 MonoAssembly *ass = tmp->data;
1978                 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);
1979                 if (!mono_assembly_close_except_image_pools (ass))
1980                         tmp->data = NULL;
1981         }
1982
1983         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1984                 MonoAssembly *ass = tmp->data;
1985                 if (ass)
1986                         mono_assembly_close_finish (ass);
1987         }
1988         g_slist_free (domain->domain_assemblies);
1989         domain->domain_assemblies = NULL;
1990
1991         /* 
1992          * Send this after the assemblies have been unloaded and the domain is still in a 
1993          * usable state.
1994          */
1995         mono_profiler_appdomain_event (domain, MONO_PROFILE_END_UNLOAD);
1996
1997         if (free_domain_hook)
1998                 free_domain_hook (domain);
1999
2000         /* FIXME: free delegate_hash_table when it's used */
2001         if (domain->search_path) {
2002                 g_strfreev (domain->search_path);
2003                 domain->search_path = NULL;
2004         }
2005         domain->create_proxy_for_type_method = NULL;
2006         domain->private_invoke_method = NULL;
2007         domain->default_context = NULL;
2008         domain->out_of_memory_ex = NULL;
2009         domain->null_reference_ex = NULL;
2010         domain->stack_overflow_ex = NULL;
2011         domain->ephemeron_tombstone = NULL;
2012         domain->entry_assembly = NULL;
2013
2014         g_free (domain->friendly_name);
2015         domain->friendly_name = NULL;
2016         g_ptr_array_free (domain->class_vtable_array, TRUE);
2017         domain->class_vtable_array = NULL;
2018         g_hash_table_destroy (domain->proxy_vtable_hash);
2019         domain->proxy_vtable_hash = NULL;
2020         if (domain->static_data_array) {
2021                 mono_gc_free_fixed (domain->static_data_array);
2022                 domain->static_data_array = NULL;
2023         }
2024         mono_internal_hash_table_destroy (&domain->jit_code_hash);
2025
2026         /*
2027          * There might still be jit info tables of this domain which
2028          * are not freed.  Since the domain cannot be in use anymore,
2029          * this will free them.
2030          */
2031         mono_thread_hazardous_try_free_all ();
2032         g_assert (domain->num_jit_info_tables == 1);
2033         jit_info_table_free (domain->jit_info_table);
2034         domain->jit_info_table = NULL;
2035         g_assert (!domain->jit_info_free_queue);
2036
2037         /* collect statistics */
2038         code_alloc = mono_code_manager_size (domain->code_mp, &code_size);
2039         total_domain_code_alloc += code_alloc;
2040         max_domain_code_alloc = MAX (max_domain_code_alloc, code_alloc);
2041         max_domain_code_size = MAX (max_domain_code_size, code_size);
2042
2043 #ifdef DEBUG_DOMAIN_UNLOAD
2044         mono_mempool_invalidate (domain->mp);
2045         mono_code_manager_invalidate (domain->code_mp);
2046 #else
2047         mono_perfcounters->loader_bytes -= mono_mempool_get_allocated (domain->mp);
2048         mono_mempool_destroy (domain->mp);
2049         domain->mp = NULL;
2050         mono_code_manager_destroy (domain->code_mp);
2051         domain->code_mp = NULL;
2052 #endif  
2053
2054         g_hash_table_destroy (domain->finalizable_objects_hash);
2055         domain->finalizable_objects_hash = NULL;
2056         if (domain->track_resurrection_objects_hash) {
2057                 g_hash_table_foreach (domain->track_resurrection_objects_hash, free_slist, NULL);
2058                 g_hash_table_destroy (domain->track_resurrection_objects_hash);
2059         }
2060         if (domain->track_resurrection_handles_hash)
2061                 g_hash_table_destroy (domain->track_resurrection_handles_hash);
2062         if (domain->method_rgctx_hash) {
2063                 g_hash_table_destroy (domain->method_rgctx_hash);
2064                 domain->method_rgctx_hash = NULL;
2065         }
2066         if (domain->generic_virtual_cases) {
2067                 g_hash_table_destroy (domain->generic_virtual_cases);
2068                 domain->generic_virtual_cases = NULL;
2069         }
2070
2071         DeleteCriticalSection (&domain->finalizable_objects_hash_lock);
2072         DeleteCriticalSection (&domain->assemblies_lock);
2073         DeleteCriticalSection (&domain->jit_code_hash_lock);
2074         DeleteCriticalSection (&domain->lock);
2075         domain->setup = NULL;
2076
2077         mono_gc_deregister_root ((char*)&(domain->MONO_DOMAIN_FIRST_GC_TRACKED));
2078
2079         /* FIXME: anything else required ? */
2080
2081         mono_gc_free_fixed (domain);
2082
2083         mono_perfcounters->loader_appdomains--;
2084
2085         if ((domain == mono_root_domain))
2086                 mono_root_domain = NULL;
2087 }
2088
2089 /**
2090  * mono_domain_get_id:
2091  * @domainid: the ID
2092  *
2093  * Returns: the a domain for a specific domain id.
2094  */
2095 MonoDomain * 
2096 mono_domain_get_by_id (gint32 domainid) 
2097 {
2098         MonoDomain * domain;
2099
2100         mono_appdomains_lock ();
2101         if (domainid < appdomain_list_size)
2102                 domain = appdomains_list [domainid];
2103         else
2104                 domain = NULL;
2105         mono_appdomains_unlock ();
2106
2107         return domain;
2108 }
2109
2110 gint32
2111 mono_domain_get_id (MonoDomain *domain)
2112 {
2113         return domain->domain_id;
2114 }
2115
2116 /*
2117  * mono_domain_alloc:
2118  *
2119  * LOCKING: Acquires the domain lock.
2120  */
2121 gpointer
2122 mono_domain_alloc (MonoDomain *domain, guint size)
2123 {
2124         gpointer res;
2125
2126         mono_domain_lock (domain);
2127         mono_perfcounters->loader_bytes += size;
2128         res = mono_mempool_alloc (domain->mp, size);
2129         mono_domain_unlock (domain);
2130
2131         return res;
2132 }
2133
2134 /*
2135  * mono_domain_alloc0:
2136  *
2137  * LOCKING: Acquires the domain lock.
2138  */
2139 gpointer
2140 mono_domain_alloc0 (MonoDomain *domain, guint size)
2141 {
2142         gpointer res;
2143
2144         mono_domain_lock (domain);
2145         mono_perfcounters->loader_bytes += size;
2146         res = mono_mempool_alloc0 (domain->mp, size);
2147         mono_domain_unlock (domain);
2148
2149         return res;
2150 }
2151
2152 /*
2153  * mono_domain_code_reserve:
2154  *
2155  * LOCKING: Acquires the domain lock.
2156  */
2157 void*
2158 mono_domain_code_reserve (MonoDomain *domain, int size)
2159 {
2160         gpointer res;
2161
2162         mono_domain_lock (domain);
2163         res = mono_code_manager_reserve (domain->code_mp, size);
2164         mono_domain_unlock (domain);
2165
2166         return res;
2167 }
2168
2169 /*
2170  * mono_domain_code_reserve_align:
2171  *
2172  * LOCKING: Acquires the domain lock.
2173  */
2174 void*
2175 mono_domain_code_reserve_align (MonoDomain *domain, int size, int alignment)
2176 {
2177         gpointer res;
2178
2179         mono_domain_lock (domain);
2180         res = mono_code_manager_reserve_align (domain->code_mp, size, alignment);
2181         mono_domain_unlock (domain);
2182
2183         return res;
2184 }
2185
2186 /*
2187  * mono_domain_code_commit:
2188  *
2189  * LOCKING: Acquires the domain lock.
2190  */
2191 void
2192 mono_domain_code_commit (MonoDomain *domain, void *data, int size, int newsize)
2193 {
2194         mono_domain_lock (domain);
2195         mono_code_manager_commit (domain->code_mp, data, size, newsize);
2196         mono_domain_unlock (domain);
2197 }
2198
2199 #if defined(__native_client_codegen__) && defined(__native_client__)
2200 /*
2201  * Given the temporary buffer (allocated by mono_domain_code_reserve) into which
2202  * we are generating code, return a pointer to the destination in the dynamic 
2203  * code segment into which the code will be copied when mono_domain_code_commit
2204  * is called.
2205  * LOCKING: Acquires the domain lock.
2206  */
2207 void *
2208 nacl_domain_get_code_dest (MonoDomain *domain, void *data)
2209 {
2210         void *dest;
2211         mono_domain_lock (domain);
2212         dest = nacl_code_manager_get_code_dest (domain->code_mp, data);
2213         mono_domain_unlock (domain);
2214         return dest;
2215 }
2216
2217 /* 
2218  * Convenience function which calls mono_domain_code_commit to validate and copy
2219  * the code. The caller sets *buf_base and *buf_size to the start and size of
2220  * the buffer (allocated by mono_domain_code_reserve), and *code_end to the byte
2221  * after the last instruction byte. On return, *buf_base will point to the start
2222  * of the copied in the code segment, and *code_end will point after the end of 
2223  * the copied code.
2224  */
2225 void
2226 nacl_domain_code_validate (MonoDomain *domain, guint8 **buf_base, int buf_size, guint8 **code_end)
2227 {
2228         guint8 *tmp = nacl_domain_get_code_dest (domain, *buf_base);
2229         mono_domain_code_commit (domain, *buf_base, buf_size, *code_end - *buf_base);
2230         *code_end = tmp + (*code_end - *buf_base);
2231         *buf_base = tmp;
2232 }
2233 #endif
2234
2235 /*
2236  * mono_domain_code_foreach:
2237  * Iterate over the code thunks of the code manager of @domain.
2238  * 
2239  * The @func callback MUST not take any locks. If it really needs to, it must respect
2240  * the locking rules of the runtime: http://www.mono-project.com/Mono:Runtime:Documentation:ThreadSafety 
2241  * LOCKING: Acquires the domain lock.
2242  */
2243
2244 void
2245 mono_domain_code_foreach (MonoDomain *domain, MonoCodeManagerFunc func, void *user_data)
2246 {
2247         mono_domain_lock (domain);
2248         mono_code_manager_foreach (domain->code_mp, func, user_data);
2249         mono_domain_unlock (domain);
2250 }
2251
2252
2253 void 
2254 mono_context_set (MonoAppContext * new_context)
2255 {
2256         SET_APPCONTEXT (new_context);
2257 }
2258
2259 MonoAppContext * 
2260 mono_context_get (void)
2261 {
2262         return GET_APPCONTEXT ();
2263 }
2264
2265 /* LOCKING: the caller holds the lock for this domain */
2266 void
2267 mono_domain_add_class_static_data (MonoDomain *domain, MonoClass *klass, gpointer data, guint32 *bitmap)
2268 {
2269         /* The first entry in the array is the index of the next free slot
2270          * and the total size of the array
2271          */
2272         int next;
2273         if (domain->static_data_array) {
2274                 int size = GPOINTER_TO_INT (domain->static_data_array [1]);
2275                 next = GPOINTER_TO_INT (domain->static_data_array [0]);
2276                 if (next >= size) {
2277                         /* 'data' is allocated by alloc_fixed */
2278                         gpointer *new_array = mono_gc_alloc_fixed (sizeof (gpointer) * (size * 2), MONO_GC_ROOT_DESCR_FOR_FIXED (size * 2));
2279                         memcpy (new_array, domain->static_data_array, sizeof (gpointer) * size);
2280                         size *= 2;
2281                         new_array [1] = GINT_TO_POINTER (size);
2282                         mono_gc_free_fixed (domain->static_data_array);
2283                         domain->static_data_array = new_array;
2284                 }
2285         } else {
2286                 int size = 32;
2287                 gpointer *new_array = mono_gc_alloc_fixed (sizeof (gpointer) * size, MONO_GC_ROOT_DESCR_FOR_FIXED (size));
2288                 next = 2;
2289                 new_array [0] = GINT_TO_POINTER (next);
2290                 new_array [1] = GINT_TO_POINTER (size);
2291                 domain->static_data_array = new_array;
2292         }
2293         domain->static_data_array [next++] = data;
2294         domain->static_data_array [0] = GINT_TO_POINTER (next);
2295 }
2296
2297 MonoImage*
2298 mono_get_corlib (void)
2299 {
2300         return mono_defaults.corlib;
2301 }
2302
2303 MonoClass*
2304 mono_get_object_class (void)
2305 {
2306         return mono_defaults.object_class;
2307 }
2308
2309 MonoClass*
2310 mono_get_byte_class (void)
2311 {
2312         return mono_defaults.byte_class;
2313 }
2314
2315 MonoClass*
2316 mono_get_void_class (void)
2317 {
2318         return mono_defaults.void_class;
2319 }
2320
2321 MonoClass*
2322 mono_get_boolean_class (void)
2323 {
2324         return mono_defaults.boolean_class;
2325 }
2326
2327 MonoClass*
2328 mono_get_sbyte_class (void)
2329 {
2330         return mono_defaults.sbyte_class;
2331 }
2332
2333 MonoClass*
2334 mono_get_int16_class (void)
2335 {
2336         return mono_defaults.int16_class;
2337 }
2338
2339 MonoClass*
2340 mono_get_uint16_class (void)
2341 {
2342         return mono_defaults.uint16_class;
2343 }
2344
2345 MonoClass*
2346 mono_get_int32_class (void)
2347 {
2348         return mono_defaults.int32_class;
2349 }
2350
2351 MonoClass*
2352 mono_get_uint32_class (void)
2353 {
2354         return mono_defaults.uint32_class;
2355 }
2356
2357 MonoClass*
2358 mono_get_intptr_class (void)
2359 {
2360         return mono_defaults.int_class;
2361 }
2362
2363 MonoClass*
2364 mono_get_uintptr_class (void)
2365 {
2366         return mono_defaults.uint_class;
2367 }
2368
2369 MonoClass*
2370 mono_get_int64_class (void)
2371 {
2372         return mono_defaults.int64_class;
2373 }
2374
2375 MonoClass*
2376 mono_get_uint64_class (void)
2377 {
2378         return mono_defaults.uint64_class;
2379 }
2380
2381 MonoClass*
2382 mono_get_single_class (void)
2383 {
2384         return mono_defaults.single_class;
2385 }
2386
2387 MonoClass*
2388 mono_get_double_class (void)
2389 {
2390         return mono_defaults.double_class;
2391 }
2392
2393 MonoClass*
2394 mono_get_char_class (void)
2395 {
2396         return mono_defaults.char_class;
2397 }
2398
2399 MonoClass*
2400 mono_get_string_class (void)
2401 {
2402         return mono_defaults.string_class;
2403 }
2404
2405 MonoClass*
2406 mono_get_enum_class (void)
2407 {
2408         return mono_defaults.enum_class;
2409 }
2410
2411 MonoClass*
2412 mono_get_array_class (void)
2413 {
2414         return mono_defaults.array_class;
2415 }
2416
2417 MonoClass*
2418 mono_get_thread_class (void)
2419 {
2420         return mono_defaults.thread_class;
2421 }
2422
2423 MonoClass*
2424 mono_get_exception_class (void)
2425 {
2426         return mono_defaults.exception_class;
2427 }
2428
2429
2430 static char* get_attribute_value (const gchar **attribute_names, 
2431                                         const gchar **attribute_values, 
2432                                         const char *att_name)
2433 {
2434         int n;
2435         for (n=0; attribute_names[n] != NULL; n++) {
2436                 if (strcmp (attribute_names[n], att_name) == 0)
2437                         return g_strdup (attribute_values[n]);
2438         }
2439         return NULL;
2440 }
2441
2442 static void start_element (GMarkupParseContext *context, 
2443                            const gchar         *element_name,
2444                            const gchar        **attribute_names,
2445                            const gchar        **attribute_values,
2446                            gpointer             user_data,
2447                            GError             **error)
2448 {
2449         AppConfigInfo* app_config = (AppConfigInfo*) user_data;
2450         
2451         if (strcmp (element_name, "configuration") == 0) {
2452                 app_config->configuration_count++;
2453                 return;
2454         }
2455         if (strcmp (element_name, "startup") == 0) {
2456                 app_config->startup_count++;
2457                 return;
2458         }
2459         
2460         if (app_config->configuration_count != 1 || app_config->startup_count != 1)
2461                 return;
2462         
2463         if (strcmp (element_name, "requiredRuntime") == 0) {
2464                 app_config->required_runtime = get_attribute_value (attribute_names, attribute_values, "version");
2465         } else if (strcmp (element_name, "supportedRuntime") == 0) {
2466                 char *version = get_attribute_value (attribute_names, attribute_values, "version");
2467                 app_config->supported_runtimes = g_slist_append (app_config->supported_runtimes, version);
2468         }
2469 }
2470
2471 static void end_element   (GMarkupParseContext *context,
2472                            const gchar         *element_name,
2473                            gpointer             user_data,
2474                            GError             **error)
2475 {
2476         AppConfigInfo* app_config = (AppConfigInfo*) user_data;
2477         
2478         if (strcmp (element_name, "configuration") == 0) {
2479                 app_config->configuration_count--;
2480         } else if (strcmp (element_name, "startup") == 0) {
2481                 app_config->startup_count--;
2482         }
2483 }
2484
2485 static const GMarkupParser 
2486 mono_parser = {
2487         start_element,
2488         end_element,
2489         NULL,
2490         NULL,
2491         NULL
2492 };
2493
2494 static AppConfigInfo *
2495 app_config_parse (const char *exe_filename)
2496 {
2497         AppConfigInfo *app_config;
2498         GMarkupParseContext *context;
2499         char *text;
2500         gsize len;
2501         const char *bundled_config;
2502         char *config_filename;
2503
2504         bundled_config = mono_config_string_for_assembly_file (exe_filename);
2505
2506         if (bundled_config) {
2507                 text = g_strdup (bundled_config);
2508                 len = strlen (text);
2509         } else {
2510                 config_filename = g_strconcat (exe_filename, ".config", NULL);
2511
2512                 if (!g_file_get_contents (config_filename, &text, &len, NULL)) {
2513                         g_free (config_filename);
2514                         return NULL;
2515                 }
2516                 g_free (config_filename);
2517         }
2518
2519         app_config = g_new0 (AppConfigInfo, 1);
2520
2521         context = g_markup_parse_context_new (&mono_parser, 0, app_config, NULL);
2522         if (g_markup_parse_context_parse (context, text, len, NULL)) {
2523                 g_markup_parse_context_end_parse (context, NULL);
2524         }
2525         g_markup_parse_context_free (context);
2526         g_free (text);
2527         return app_config;
2528 }
2529
2530 static void 
2531 app_config_free (AppConfigInfo* app_config)
2532 {
2533         char *rt;
2534         GSList *list = app_config->supported_runtimes;
2535         while (list != NULL) {
2536                 rt = (char*)list->data;
2537                 g_free (rt);
2538                 list = g_slist_next (list);
2539         }
2540         g_slist_free (app_config->supported_runtimes);
2541         g_free (app_config->required_runtime);
2542         g_free (app_config);
2543 }
2544
2545
2546 static const MonoRuntimeInfo*
2547 get_runtime_by_version (const char *version)
2548 {
2549         int n;
2550         int max = G_N_ELEMENTS (supported_runtimes);
2551         gboolean do_partial_match;
2552         int vlen;
2553
2554         if (!version)
2555                 return NULL;
2556
2557         vlen = strlen (version);
2558         if (vlen >= 4 && version [1] - '0' >= 4)
2559                 do_partial_match = TRUE;
2560         else
2561                 do_partial_match = FALSE;
2562
2563         for (n=0; n<max; n++) {
2564                 if (do_partial_match && strncmp (version, supported_runtimes[n].runtime_version, vlen) == 0)
2565                         return &supported_runtimes[n];
2566                 if (strcmp (version, supported_runtimes[n].runtime_version) == 0)
2567                         return &supported_runtimes[n];
2568         }
2569         return NULL;
2570 }
2571
2572 static void
2573 get_runtimes_from_exe (const char *exe_file, MonoImage **exe_image, const MonoRuntimeInfo** runtimes)
2574 {
2575         AppConfigInfo* app_config;
2576         char *version;
2577         const MonoRuntimeInfo* runtime = NULL;
2578         MonoImage *image = NULL;
2579         
2580         app_config = app_config_parse (exe_file);
2581         
2582         if (app_config != NULL) {
2583                 /* Check supportedRuntime elements, if none is supported, fail.
2584                  * If there are no such elements, look for a requiredRuntime element.
2585                  */
2586                 if (app_config->supported_runtimes != NULL) {
2587                         int n = 0;
2588                         GSList *list = app_config->supported_runtimes;
2589                         while (list != NULL) {
2590                                 version = (char*) list->data;
2591                                 runtime = get_runtime_by_version (version);
2592                                 if (runtime != NULL)
2593                                         runtimes [n++] = runtime;
2594                                 list = g_slist_next (list);
2595                         }
2596                         runtimes [n] = NULL;
2597                         app_config_free (app_config);
2598                         return;
2599                 }
2600                 
2601                 /* Check the requiredRuntime element. This is for 1.0 apps only. */
2602                 if (app_config->required_runtime != NULL) {
2603                         runtimes [0] = get_runtime_by_version (app_config->required_runtime);
2604                         runtimes [1] = NULL;
2605                         app_config_free (app_config);
2606                         return;
2607                 }
2608                 app_config_free (app_config);
2609         }
2610         
2611         /* Look for a runtime with the exact version */
2612         image = mono_assembly_open_from_bundle (exe_file, NULL, FALSE);
2613
2614         if (image == NULL)
2615                 image = mono_image_open (exe_file, NULL);
2616
2617         if (image == NULL) {
2618                 /* The image is wrong or the file was not found. In this case return
2619                  * a default runtime and leave to the initialization method the work of
2620                  * reporting the error.
2621                  */
2622                 runtimes [0] = get_runtime_by_version (DEFAULT_RUNTIME_VERSION);
2623                 runtimes [1] = NULL;
2624                 return;
2625         }
2626
2627         *exe_image = image;
2628
2629         runtimes [0] = get_runtime_by_version (image->version);
2630         runtimes [1] = NULL;
2631 }
2632
2633
2634 /**
2635  * mono_get_runtime_info:
2636  *
2637  * Returns: the version of the current runtime instance.
2638  */
2639 const MonoRuntimeInfo*
2640 mono_get_runtime_info (void)
2641 {
2642         return current_runtime;
2643 }
2644
2645 gchar *
2646 mono_debugger_check_runtime_version (const char *filename)
2647 {
2648         const MonoRuntimeInfo* runtimes [G_N_ELEMENTS (supported_runtimes) + 1];
2649         const MonoRuntimeInfo *rinfo;
2650         MonoImage *image;
2651
2652         get_runtimes_from_exe (filename, &image, runtimes);
2653         rinfo = runtimes [0];
2654
2655         if (!rinfo)
2656                 return g_strdup_printf ("Cannot get runtime version from assembly `%s'", filename);
2657
2658         if (rinfo != current_runtime)
2659                 return g_strdup_printf ("The Mono Debugger is currently using the `%s' runtime, but "
2660                                         "the assembly `%s' requires version `%s'", current_runtime->runtime_version,
2661                                         filename, rinfo->runtime_version);
2662
2663         return NULL;
2664 }
2665
2666 /**
2667  * mono_framework_version:
2668  *
2669  * Return the major version of the framework curently executing.
2670  */
2671 int
2672 mono_framework_version (void)
2673 {
2674         return current_runtime->framework_version [0] - '0';
2675 }
2676