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