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