in mono/mono/mini:
[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  * (C) 2001 Ximian, Inc.
9  */
10
11 #include <config.h>
12 #include <glib.h>
13 #include <string.h>
14 #include <sys/stat.h>
15
16 #include <mono/os/gc_wrapper.h>
17
18 #include <mono/utils/mono-compiler.h>
19 #include <mono/utils/mono-logger.h>
20 #include <mono/utils/mono-membar.h>
21 #include <mono/metadata/object.h>
22 #include <mono/metadata/object-internals.h>
23 #include <mono/metadata/domain-internals.h>
24 #include <mono/metadata/class-internals.h>
25 #include <mono/metadata/assembly.h>
26 #include <mono/metadata/exception.h>
27 #include <mono/metadata/cil-coff.h>
28 #include <mono/metadata/rawbuffer.h>
29 #include <mono/metadata/metadata-internals.h>
30 #include <mono/metadata/gc-internal.h>
31 #include <mono/metadata/appdomain.h>
32 #include <mono/metadata/mono-debug-debugger.h>
33 #include <mono/metadata/mono-config.h>
34 #include <mono/metadata/threads-types.h>
35 #include <metadata/threads.h>
36
37 /* #define DEBUG_DOMAIN_UNLOAD */
38
39 /* we need to use both the Tls* functions and __thread because
40  * some archs may generate faster jit code with one meachanism
41  * or the other (we used to do it because tls slots were GC-tracked,
42  * but we can't depend on this).
43  */
44 static guint32 appdomain_thread_id = -1;
45  
46 #ifdef HAVE_KW_THREAD
47 static __thread MonoDomain * tls_appdomain MONO_TLS_FAST;
48 #define GET_APPDOMAIN() tls_appdomain
49 #define SET_APPDOMAIN(x) do { \
50         tls_appdomain = x; \
51         TlsSetValue (appdomain_thread_id, x); \
52 } while (FALSE)
53
54 #else
55
56 #define GET_APPDOMAIN() ((MonoDomain *)TlsGetValue (appdomain_thread_id))
57 #define SET_APPDOMAIN(x) TlsSetValue (appdomain_thread_id, x);
58
59 #endif
60
61 #define GET_APPCONTEXT() (mono_thread_current ()->current_appcontext)
62 #define SET_APPCONTEXT(x) MONO_OBJECT_SETREF (mono_thread_current (), current_appcontext, (x))
63
64 static guint16 appdomain_list_size = 0;
65 static guint16 appdomain_next = 0;
66 static MonoDomain **appdomains_list = NULL;
67
68 #define mono_appdomains_lock() EnterCriticalSection (&appdomains_mutex)
69 #define mono_appdomains_unlock() LeaveCriticalSection (&appdomains_mutex)
70 static CRITICAL_SECTION appdomains_mutex;
71
72 static MonoDomain *mono_root_domain = NULL;
73
74 /* AppConfigInfo: Information about runtime versions supported by an 
75  * aplication.
76  */
77 typedef struct {
78         GSList *supported_runtimes;
79         char *required_runtime;
80         int configuration_count;
81         int startup_count;
82 } AppConfigInfo;
83
84 /*
85  * AotModuleInfo: Contains information about AOT modules.
86  */
87 typedef struct {
88         MonoImage *image;
89         gpointer start, end;
90 } AotModuleInfo;
91
92 static const MonoRuntimeInfo *current_runtime = NULL;
93
94 static MonoJitInfoFindInAot jit_info_find_in_aot_func = NULL;
95
96 /*
97  * Contains information about AOT loaded code.
98  */
99 static MonoAotModuleInfoTable *aot_modules = NULL;
100
101 /* This is the list of runtime versions supported by this JIT.
102  */
103 static const MonoRuntimeInfo supported_runtimes[] = {
104         {"v1.0.3705", "1.0", { {1,0,5000,0}, {7,0,5000,0} }     },
105         {"v1.1.4322", "1.0", { {1,0,5000,0}, {7,0,5000,0} }     },
106         {"v2.0.50215","2.0", { {2,0,0,0},    {8,0,0,0} }        },
107         {"v2.0.50727","2.0", { {2,0,0,0},    {8,0,0,0} }        },
108         {"moonlight", "2.1", { {2,1,0,0},    {9,0,0,0} }    },
109 };
110
111
112 /* The stable runtime version */
113 #define DEFAULT_RUNTIME_VERSION "v1.1.4322"
114
115 static void
116 get_runtimes_from_exe (const char *exe_file, const MonoRuntimeInfo** runtimes);
117
118 static const MonoRuntimeInfo*
119 get_runtime_by_version (const char *version);
120
121 static MonoImage*
122 mono_jit_info_find_aot_module (guint8* addr);
123
124 guint32
125 mono_domain_get_tls_key (void)
126 {
127         return appdomain_thread_id;
128 }
129
130 gint32
131 mono_domain_get_tls_offset (void)
132 {
133         int offset = -1;
134         MONO_THREAD_VAR_OFFSET (tls_appdomain, offset);
135 /*      __asm ("jmp 1f; .section writetext, \"awx\"; 1: movl $tls_appdomain@ntpoff, %0; jmp 2f; .previous; 2:" 
136                 : "=r" (offset));*/
137         return offset;
138 }
139
140 #define JIT_INFO_TABLE_FILL_RATIO_NOM           3
141 #define JIT_INFO_TABLE_FILL_RATIO_DENOM         4
142 #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)
143
144 #define JIT_INFO_TABLE_LOW_WATERMARK(n)         ((n) / 2)
145 #define JIT_INFO_TABLE_HIGH_WATERMARK(n)        ((n) * 5 / 6)
146
147 #define IS_JIT_INFO_TOMBSTONE(ji)       ((ji)->method == NULL)
148
149 #define JIT_INFO_TABLE_HAZARD_INDEX             0
150 #define JIT_INFO_HAZARD_INDEX                   1
151
152 static int
153 jit_info_table_num_elements (MonoJitInfoTable *table)
154 {
155         int i;
156         int num_elements = 0;
157
158         for (i = 0; i < table->num_chunks; ++i) {
159                 MonoJitInfoTableChunk *chunk = table->chunks [i];
160                 int chunk_num_elements = chunk->num_elements;
161                 int j;
162
163                 for (j = 0; j < chunk_num_elements; ++j) {
164                         if (!IS_JIT_INFO_TOMBSTONE (chunk->data [j]))
165                                 ++num_elements;
166                 }
167         }
168
169         return num_elements;
170 }
171
172 static MonoJitInfoTableChunk*
173 jit_info_table_new_chunk (void)
174 {
175         MonoJitInfoTableChunk *chunk = g_new0 (MonoJitInfoTableChunk, 1);
176         chunk->refcount = 1;
177
178         return chunk;
179 }
180
181 static MonoJitInfoTable *
182 jit_info_table_new (void)
183 {
184         MonoJitInfoTable *table = g_malloc0 (sizeof (MonoJitInfoTable) + sizeof (MonoJitInfoTableChunk*));
185
186         table->num_chunks = 1;
187         table->chunks [0] = jit_info_table_new_chunk ();
188
189         return table;
190 }
191
192 static void
193 jit_info_table_free (MonoJitInfoTable *table)
194 {
195         int i;
196         int num_chunks = table->num_chunks;
197
198         /* At this point we assume that there are no other threads
199            still accessing the table, so we don't have to worry about
200            hazardous pointers. */
201
202         for (i = 0; i < num_chunks; ++i) {
203                 MonoJitInfoTableChunk *chunk = table->chunks [i];
204                 int num_elements;
205                 int j;
206
207                 if (--chunk->refcount > 0)
208                         continue;
209
210                 num_elements = chunk->num_elements;
211                 for (j = 0; j < num_elements; ++j) {
212                         MonoJitInfo *ji = chunk->data [j];
213
214                         if (IS_JIT_INFO_TOMBSTONE (ji))
215                                 g_free (ji);
216                 }
217
218                 g_free (chunk);
219         }
220
221         g_free (table);
222 }
223
224 /* Can be called with hp==NULL, in which case it acts as an ordinary
225    pointer fetch.  It's used that way indirectly from
226    mono_jit_info_table_add(), which doesn't have to care about hazards
227    because it holds the respective domain lock. */
228 static gpointer
229 get_hazardous_pointer (gpointer volatile *pp, MonoThreadHazardPointers *hp, int hazard_index)
230 {
231         gpointer p;
232
233         for (;;) {
234                 /* Get the pointer */
235                 p = *pp;
236                 /* If we don't have hazard pointers just return the
237                    pointer. */
238                 if (!hp)
239                         return p;
240                 /* Make it hazardous */
241                 mono_hazard_pointer_set (hp, hazard_index, p);
242                 /* Check that it's still the same.  If not, try
243                    again. */
244                 if (*pp != p) {
245                         mono_hazard_pointer_clear (hp, hazard_index);
246                         continue;
247                 }
248                 break;
249         }
250
251         return p;
252 }
253
254 /* The jit_info_table is sorted in ascending order by the end
255  * addresses of the compiled methods.  The reason why we have to do
256  * this is that once we introduce tombstones, it becomes possible for
257  * code ranges to overlap, and if we sort by code start and insert at
258  * the back of the table, we cannot guarantee that we won't overlook
259  * an entry.
260  *
261  * There are actually two possible ways to do the sorting and
262  * inserting which work with our lock-free mechanism:
263  *
264  * 1. Sort by start address and insert at the front.  When looking for
265  * an entry, find the last one with a start address lower than the one
266  * you're looking for, then work your way to the front of the table.
267  *
268  * 2. Sort by end address and insert at the back.  When looking for an
269  * entry, find the first one with an end address higher than the one
270  * you're looking for, then work your way to the end of the table.
271  *
272  * We chose the latter out of convenience.
273  */
274 static int
275 jit_info_table_index (MonoJitInfoTable *table, gint8 *addr)
276 {
277         int left = 0, right = table->num_chunks;
278
279         g_assert (left < right);
280
281         do {
282                 int pos = (left + right) / 2;
283                 MonoJitInfoTableChunk *chunk = table->chunks [pos];
284
285                 if (addr < chunk->last_code_end)
286                         right = pos;
287                 else
288                         left = pos + 1;
289         } while (left < right);
290         g_assert (left == right);
291
292         if (left >= table->num_chunks)
293                 return table->num_chunks - 1;
294         return left;
295 }
296
297 static int
298 jit_info_table_chunk_index (MonoJitInfoTableChunk *chunk, MonoThreadHazardPointers *hp, gint8 *addr)
299 {
300         int left = 0, right = chunk->num_elements;
301
302         while (left < right) {
303                 int pos = (left + right) / 2;
304                 MonoJitInfo *ji = get_hazardous_pointer((gpointer volatile*)&chunk->data [pos], hp, JIT_INFO_HAZARD_INDEX);
305                 gint8 *code_end = (gint8*)ji->code_start + ji->code_size;
306
307                 if (addr < code_end)
308                         right = pos;
309                 else
310                         left = pos + 1;
311         }
312         g_assert (left == right);
313
314         return left;
315 }
316
317 MonoJitInfo*
318 mono_jit_info_table_find (MonoDomain *domain, char *addr)
319 {
320         MonoJitInfoTable *table;
321         MonoJitInfo *ji;
322         int chunk_pos, pos;
323         MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
324
325         ++mono_stats.jit_info_table_lookup_count;
326
327         /* First we have to get the domain's jit_info_table.  This is
328            complicated by the fact that a writer might substitute a
329            new table and free the old one.  What the writer guarantees
330            us is that it looks at the hazard pointers after it has
331            changed the jit_info_table pointer.  So, if we guard the
332            table by a hazard pointer and make sure that the pointer is
333            still there after we've made it hazardous, we don't have to
334            worry about the writer freeing the table. */
335         table = get_hazardous_pointer ((gpointer volatile*)&domain->jit_info_table, hp, JIT_INFO_TABLE_HAZARD_INDEX);
336
337         chunk_pos = jit_info_table_index (table, (gint8*)addr);
338         g_assert (chunk_pos < table->num_chunks);
339
340         pos = jit_info_table_chunk_index (table->chunks [chunk_pos], hp, (gint8*)addr);
341
342         /* We now have a position that's very close to that of the
343            first element whose end address is higher than the one
344            we're looking for.  If we don't have the exact position,
345            then we have a position below that one, so we'll just
346            search upward until we find our element. */
347         do {
348                 MonoJitInfoTableChunk *chunk = table->chunks [chunk_pos];
349
350                 while (pos < chunk->num_elements) {
351                         ji = get_hazardous_pointer ((gpointer volatile*)&chunk->data [pos], hp, JIT_INFO_HAZARD_INDEX);
352
353                         ++pos;
354
355                         if (IS_JIT_INFO_TOMBSTONE (ji)) {
356                                 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
357                                 continue;
358                         }
359                         if ((gint8*)addr >= (gint8*)ji->code_start
360                                         && (gint8*)addr < (gint8*)ji->code_start + ji->code_size) {
361                                 mono_hazard_pointer_clear (hp, JIT_INFO_TABLE_HAZARD_INDEX);
362                                 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
363                                 return ji;
364                         }
365
366                         /* If we find a non-tombstone element which is already
367                            beyond what we're looking for, we have to end the
368                            search. */
369                         if ((gint8*)addr < (gint8*)ji->code_start)
370                                 break;
371                 }
372
373                 ++chunk_pos;
374                 pos = 0;
375          } while (chunk_pos < table->num_chunks);
376
377         mono_hazard_pointer_clear (hp, JIT_INFO_TABLE_HAZARD_INDEX);
378         mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
379
380         /* maybe it is shared code, so we also search in the root domain */
381         ji = NULL;
382         if (domain != mono_root_domain)
383                 ji = mono_jit_info_table_find (mono_root_domain, addr);
384
385         if (ji == NULL) {
386                 /* Maybe its an AOT module */
387                 MonoImage *image = mono_jit_info_find_aot_module ((guint8*)addr);
388                 if (image)
389                         ji = jit_info_find_in_aot_func (domain, image, addr);
390         }
391         
392         return ji;
393 }
394
395 static void
396 jit_info_table_check (MonoJitInfoTable *table)
397 {
398         int i;
399
400         for (i = 0; i < table->num_chunks; ++i) {
401                 MonoJitInfoTableChunk *chunk = table->chunks [i];
402                 int j;
403
404                 g_assert (chunk->refcount > 0 /* && chunk->refcount <= 8 */);
405                 if (chunk->refcount > 10)
406                         printf("warning: chunk refcount is %d\n", chunk->refcount);
407                 g_assert (chunk->num_elements <= MONO_JIT_INFO_TABLE_CHUNK_SIZE);
408
409                 for (j = 0; j < chunk->num_elements; ++j) {
410                         MonoJitInfo *this = chunk->data [j];
411                         MonoJitInfo *next;
412
413                         g_assert ((gint8*)this->code_start + this->code_size <= chunk->last_code_end);
414
415                         if (j < chunk->num_elements - 1)
416                                 next = chunk->data [j + 1];
417                         else if (i < table->num_chunks - 1) {
418                                 int k;
419
420                                 for (k = i + 1; k < table->num_chunks; ++k)
421                                         if (table->chunks [k]->num_elements > 0)
422                                                 break;
423
424                                 if (k >= table->num_chunks)
425                                         return;
426
427                                 g_assert (table->chunks [k]->num_elements > 0);
428                                 next = table->chunks [k]->data [0];
429                         } else
430                                 return;
431
432                         g_assert ((gint8*)this->code_start + this->code_size <= (gint8*)next->code_start + next->code_size);
433                 }
434         }
435 }
436
437 static MonoJitInfoTable*
438 jit_info_table_realloc (MonoJitInfoTable *old)
439 {
440         int i;
441         int num_elements = jit_info_table_num_elements (old);
442         int required_size;
443         int num_chunks;
444         int new_chunk, new_element;
445         MonoJitInfoTable *new;
446
447         /* number of needed places for elements needed */
448         required_size = (int)((long)num_elements * JIT_INFO_TABLE_FILL_RATIO_DENOM / JIT_INFO_TABLE_FILL_RATIO_NOM);
449         num_chunks = (required_size + MONO_JIT_INFO_TABLE_CHUNK_SIZE - 1) / MONO_JIT_INFO_TABLE_CHUNK_SIZE;
450
451         new = g_malloc (sizeof (MonoJitInfoTable) + sizeof (MonoJitInfoTableChunk*) * num_chunks);
452         new->num_chunks = num_chunks;
453
454         for (i = 0; i < num_chunks; ++i)
455                 new->chunks [i] = jit_info_table_new_chunk ();
456
457         new_chunk = 0;
458         new_element = 0;
459         for (i = 0; i < old->num_chunks; ++i) {
460                 MonoJitInfoTableChunk *chunk = old->chunks [i];
461                 int chunk_num_elements = chunk->num_elements;
462                 int j;
463
464                 for (j = 0; j < chunk_num_elements; ++j) {
465                         if (!IS_JIT_INFO_TOMBSTONE (chunk->data [j])) {
466                                 g_assert (new_chunk < num_chunks);
467                                 new->chunks [new_chunk]->data [new_element] = chunk->data [j];
468                                 if (++new_element >= JIT_INFO_TABLE_FILLED_NUM_ELEMENTS) {
469                                         new->chunks [new_chunk]->num_elements = new_element;
470                                         ++new_chunk;
471                                         new_element = 0;
472                                 }
473                         }
474                 }
475         }
476
477         if (new_chunk < num_chunks) {
478                 g_assert (new_chunk == num_chunks - 1);
479                 new->chunks [new_chunk]->num_elements = new_element;
480                 g_assert (new->chunks [new_chunk]->num_elements > 0);
481         }
482
483         for (i = 0; i < num_chunks; ++i) {
484                 MonoJitInfoTableChunk *chunk = new->chunks [i];
485                 MonoJitInfo *ji = chunk->data [chunk->num_elements - 1];
486
487                 new->chunks [i]->last_code_end = (gint8*)ji->code_start + ji->code_size;
488         }
489
490         return new;
491 }
492
493 static void
494 jit_info_table_split_chunk (MonoJitInfoTableChunk *chunk, MonoJitInfoTableChunk **new1p, MonoJitInfoTableChunk **new2p)
495 {
496         MonoJitInfoTableChunk *new1 = jit_info_table_new_chunk ();
497         MonoJitInfoTableChunk *new2 = jit_info_table_new_chunk ();
498
499         g_assert (chunk->num_elements == MONO_JIT_INFO_TABLE_CHUNK_SIZE);
500
501         new1->num_elements = MONO_JIT_INFO_TABLE_CHUNK_SIZE / 2;
502         new2->num_elements = MONO_JIT_INFO_TABLE_CHUNK_SIZE - new1->num_elements;
503
504         memcpy ((void*)new1->data, (void*)chunk->data, sizeof (MonoJitInfo*) * new1->num_elements);
505         memcpy ((void*)new2->data, (void*)(chunk->data + new1->num_elements), sizeof (MonoJitInfo*) * new2->num_elements);
506
507         new1->last_code_end = (gint8*)new1->data [new1->num_elements - 1]->code_start
508                 + new1->data [new1->num_elements - 1]->code_size;
509         new2->last_code_end = (gint8*)new2->data [new2->num_elements - 1]->code_start
510                 + new2->data [new2->num_elements - 1]->code_size;
511
512         *new1p = new1;
513         *new2p = new2;
514 }
515
516 static MonoJitInfoTable*
517 jit_info_table_copy_and_split_chunk (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
518 {
519         MonoJitInfoTable *new_table = g_malloc (sizeof (MonoJitInfoTable)
520                 + sizeof (MonoJitInfoTableChunk*) * (table->num_chunks + 1));
521         int i, j;
522
523         new_table->num_chunks = table->num_chunks + 1;
524
525         j = 0;
526         for (i = 0; i < table->num_chunks; ++i) {
527                 if (table->chunks [i] == chunk) {
528                         jit_info_table_split_chunk (chunk, &new_table->chunks [j], &new_table->chunks [j + 1]);
529                         j += 2;
530                 } else {
531                         new_table->chunks [j] = table->chunks [i];
532                         ++new_table->chunks [j]->refcount;
533                         ++j;
534                 }
535         }
536
537         g_assert (j == new_table->num_chunks);
538
539         return new_table;
540 }
541
542 static MonoJitInfoTableChunk*
543 jit_info_table_purify_chunk (MonoJitInfoTableChunk *old)
544 {
545         MonoJitInfoTableChunk *new = jit_info_table_new_chunk ();
546         int i, j;
547
548         j = 0;
549         for (i = 0; i < old->num_elements; ++i) {
550                 if (!IS_JIT_INFO_TOMBSTONE (old->data [i]))
551                         new->data [j++] = old->data [i];
552         }
553
554         new->num_elements = j;
555         if (new->num_elements > 0)
556                 new->last_code_end = (gint8*)new->data [j - 1]->code_start + new->data [j - 1]->code_size;
557         else
558                 new->last_code_end = old->last_code_end;
559
560         return new;
561 }
562
563 static MonoJitInfoTable*
564 jit_info_table_copy_and_purify_chunk (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
565 {
566         MonoJitInfoTable *new_table = g_malloc (sizeof (MonoJitInfoTable)
567                 + sizeof (MonoJitInfoTableChunk*) * table->num_chunks);
568         int i, j;
569
570         new_table->num_chunks = table->num_chunks;
571
572         j = 0;
573         for (i = 0; i < table->num_chunks; ++i) {
574                 if (table->chunks [i] == chunk)
575                         new_table->chunks [j++] = jit_info_table_purify_chunk (table->chunks [i]);
576                 else {
577                         new_table->chunks [j] = table->chunks [i];
578                         ++new_table->chunks [j]->refcount;
579                         ++j;
580                 }
581         }
582
583         g_assert (j == new_table->num_chunks);
584
585         return new_table;
586 }
587
588 /* As we add an element to the table the case can arise that the chunk
589  * to which we need to add is already full.  In that case we have to
590  * allocate a new table and do something about that chunk.  We have
591  * several strategies:
592  *
593  * If the number of elements in the table is below the low watermark
594  * or above the high watermark, we reallocate the whole table.
595  * Otherwise we only concern ourselves with the overflowing chunk:
596  *
597  * If there are no tombstones in the chunk then we split the chunk in
598  * two, each half full.
599  *
600  * If the chunk does contain tombstones, we just make a new copy of
601  * the chunk without the tombstones, which will have room for at least
602  * the one element we have to add.
603  */
604 static MonoJitInfoTable*
605 jit_info_table_chunk_overflow (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
606 {
607         int num_elements = jit_info_table_num_elements (table);
608         int i;
609
610         if (num_elements < JIT_INFO_TABLE_LOW_WATERMARK (table->num_chunks * MONO_JIT_INFO_TABLE_CHUNK_SIZE)
611                         || num_elements > JIT_INFO_TABLE_HIGH_WATERMARK (table->num_chunks * MONO_JIT_INFO_TABLE_CHUNK_SIZE)) {
612                 //printf ("reallocing table\n");
613                 return jit_info_table_realloc (table);
614         }
615
616         /* count the number of non-tombstone elements in the chunk */
617         num_elements = 0;
618         for (i = 0; i < chunk->num_elements; ++i) {
619                 if (!IS_JIT_INFO_TOMBSTONE (chunk->data [i]))
620                         ++num_elements;
621         }
622
623         if (num_elements == MONO_JIT_INFO_TABLE_CHUNK_SIZE) {
624                 //printf ("splitting chunk\n");
625                 return jit_info_table_copy_and_split_chunk (table, chunk);
626         }
627
628         //printf ("purifying chunk\n");
629         return jit_info_table_copy_and_purify_chunk (table, chunk);
630 }
631
632 /* We add elements to the table by first making space for them by
633  * shifting the elements at the back to the right, one at a time.
634  * This results in duplicate entries during the process, but during
635  * all the time the table is in a sorted state.  Also, when an element
636  * is replaced by another one, the element that replaces it has an end
637  * address that is equal to or lower than that of the replaced
638  * element.  That property is necessary to guarantee that when
639  * searching for an element we end up at a position not higher than
640  * the one we're looking for (i.e. we either find the element directly
641  * or we end up to the left of it).
642  */
643 void
644 mono_jit_info_table_add (MonoDomain *domain, MonoJitInfo *ji)
645 {
646         MonoJitInfoTable *table;
647         int chunk_pos, pos;
648         MonoJitInfoTableChunk *chunk;
649         int num_elements;
650         int i;
651
652         g_assert (ji->method != NULL);
653
654         mono_domain_lock (domain);
655
656         ++mono_stats.jit_info_table_insert_count;
657
658         table = domain->jit_info_table;
659
660  restart:
661         chunk_pos = jit_info_table_index (table, (gint8*)ji->code_start + ji->code_size);
662         g_assert (chunk_pos < table->num_chunks);
663         chunk = table->chunks [chunk_pos];
664
665         if (chunk->num_elements >= MONO_JIT_INFO_TABLE_CHUNK_SIZE) {
666                 MonoJitInfoTable *new_table = jit_info_table_chunk_overflow (table, chunk);
667
668                 /* Debugging code, should be removed. */
669                 //jit_info_table_check (new_table);
670
671                 domain->jit_info_table = new_table;
672                 mono_memory_barrier ();
673                 mono_thread_hazardous_free_or_queue (table, (MonoHazardousFreeFunc)jit_info_table_free);
674                 table = new_table;
675
676                 goto restart;
677         }
678
679         /* Debugging code, should be removed. */
680         //jit_info_table_check (table);
681
682         num_elements = chunk->num_elements;
683
684         pos = jit_info_table_chunk_index (chunk, NULL, (gint8*)ji->code_start + ji->code_size);
685
686         /* First we need to size up the chunk by one, by copying the
687            last item, or inserting the first one, if the table is
688            empty. */
689         if (num_elements > 0)
690                 chunk->data [num_elements] = chunk->data [num_elements - 1];
691         else
692                 chunk->data [0] = ji;
693         mono_memory_write_barrier ();
694         chunk->num_elements = ++num_elements;
695
696         /* Shift the elements up one by one. */
697         for (i = num_elements - 2; i >= pos; --i) {
698                 mono_memory_write_barrier ();
699                 chunk->data [i + 1] = chunk->data [i];
700         }
701
702         /* Now we have room and can insert the new item. */
703         mono_memory_write_barrier ();
704         chunk->data [pos] = ji;
705
706         /* Set the high code end address chunk entry. */
707         chunk->last_code_end = (gint8*)chunk->data [chunk->num_elements - 1]->code_start
708                 + chunk->data [chunk->num_elements - 1]->code_size;
709
710         /* Debugging code, should be removed. */
711         //jit_info_table_check (table);
712
713         mono_domain_unlock (domain);
714 }
715
716 static MonoJitInfo*
717 mono_jit_info_make_tombstone (MonoJitInfo *ji)
718 {
719         MonoJitInfo *tombstone = g_new0 (MonoJitInfo, 1);
720
721         tombstone->code_start = ji->code_start;
722         tombstone->code_size = ji->code_size;
723         tombstone->method = NULL;
724
725         return tombstone;
726 }
727
728 void
729 mono_jit_info_table_remove (MonoDomain *domain, MonoJitInfo *ji)
730 {
731         MonoJitInfoTable *table;
732         MonoJitInfoTableChunk *chunk;
733         gpointer start = ji->code_start;
734         int chunk_pos, pos;
735
736         mono_domain_lock (domain);
737         table = domain->jit_info_table;
738
739         ++mono_stats.jit_info_table_remove_count;
740
741         chunk_pos = jit_info_table_index (table, start);
742         g_assert (chunk_pos < table->num_chunks);
743
744         pos = jit_info_table_chunk_index (table->chunks [chunk_pos], NULL, start);
745
746         do {
747                 chunk = table->chunks [chunk_pos];
748
749                 while (pos < chunk->num_elements) {
750                         if (chunk->data [pos] == ji)
751                                 goto found;
752
753                         g_assert (IS_JIT_INFO_TOMBSTONE (chunk->data [pos]));
754                         g_assert ((guint8*)chunk->data [pos]->code_start + chunk->data [pos]->code_size
755                                 <= (guint8*)ji->code_start + ji->code_size);
756
757                         ++pos;
758                 }
759
760                 ++chunk_pos;
761                 pos = 0;
762         } while (chunk_pos < table->num_chunks);
763
764  found:
765         g_assert (chunk->data [pos] == ji);
766
767         chunk->data [pos] = mono_jit_info_make_tombstone (ji);
768
769         /* Debugging code, should be removed. */
770         //jit_info_table_check (table);
771
772         mono_domain_unlock (domain);
773 }
774
775 static MonoAotModuleInfoTable*
776 mono_aot_module_info_table_new (void)
777 {
778         return g_array_new (FALSE, FALSE, sizeof (gpointer));
779 }
780
781 static int
782 aot_info_table_index (MonoAotModuleInfoTable *table, char *addr)
783 {
784         int left = 0, right = table->len;
785
786         while (left < right) {
787                 int pos = (left + right) / 2;
788                 AotModuleInfo *ainfo = g_array_index (table, gpointer, pos);
789                 char *start = ainfo->start;
790                 char *end = ainfo->end;
791
792                 if (addr < start)
793                         right = pos;
794                 else if (addr >= end) 
795                         left = pos + 1;
796                 else
797                         return pos;
798         }
799
800         return left;
801 }
802
803 void
804 mono_jit_info_add_aot_module (MonoImage *image, gpointer start, gpointer end)
805 {
806         AotModuleInfo *ainfo = g_new0 (AotModuleInfo, 1);
807         int pos;
808
809         ainfo->image = image;
810         ainfo->start = start;
811         ainfo->end = end;
812
813         mono_appdomains_lock ();
814
815         if (!aot_modules)
816                 aot_modules = mono_aot_module_info_table_new ();
817
818         pos = aot_info_table_index (aot_modules, start);
819
820         g_array_insert_val (aot_modules, pos, ainfo);
821
822         mono_appdomains_unlock ();
823 }
824
825 static MonoImage*
826 mono_jit_info_find_aot_module (guint8* addr)
827 {
828         guint left = 0, right;
829
830         if (!aot_modules)
831                 return NULL;
832
833         mono_appdomains_lock ();
834
835         right = aot_modules->len;
836         while (left < right) {
837                 guint pos = (left + right) / 2;
838                 AotModuleInfo *ai = g_array_index (aot_modules, gpointer, pos);
839
840                 if (addr < (guint8*)ai->start)
841                         right = pos;
842                 else if (addr >= (guint8*)ai->end)
843                         left = pos + 1;
844                 else {
845                         mono_appdomains_unlock ();
846                         return ai->image;
847                 }
848         }
849
850         mono_appdomains_unlock ();
851
852         return NULL;
853 }
854
855 void
856 mono_install_jit_info_find_in_aot (MonoJitInfoFindInAot func)
857 {
858         jit_info_find_in_aot_func = func;
859 }
860
861 gpointer
862 mono_jit_info_get_code_start (MonoJitInfo* ji)
863 {
864         return ji->code_start;
865 }
866
867 int
868 mono_jit_info_get_code_size (MonoJitInfo* ji)
869 {
870         return ji->code_size;
871 }
872
873 MonoMethod*
874 mono_jit_info_get_method (MonoJitInfo* ji)
875 {
876         return ji->method;
877 }
878
879 static gpointer
880 jit_info_key_extract (gpointer value)
881 {
882         MonoJitInfo *info = (MonoJitInfo*)value;
883
884         return info->method;
885 }
886
887 static gpointer*
888 jit_info_next_value (gpointer value)
889 {
890         MonoJitInfo *info = (MonoJitInfo*)value;
891
892         return (gpointer*)&info->next_jit_code_hash;
893 }
894
895 void
896 mono_jit_code_hash_init (MonoInternalHashTable *jit_code_hash)
897 {
898         mono_internal_hash_table_init (jit_code_hash,
899                                        mono_aligned_addr_hash,
900                                        jit_info_key_extract,
901                                        jit_info_next_value);
902 }
903
904 /**
905  * mono_string_equal:
906  * @s1: First string to compare
907  * @s2: Second string to compare
908  *
909  * Returns FALSE if the strings differ.
910  */
911 gboolean
912 mono_string_equal (MonoString *s1, MonoString *s2)
913 {
914         int l1 = mono_string_length (s1);
915         int l2 = mono_string_length (s2);
916
917         if (s1 == s2)
918                 return TRUE;
919         if (l1 != l2)
920                 return FALSE;
921
922         return memcmp (mono_string_chars (s1), mono_string_chars (s2), l1 * 2) == 0; 
923 }
924
925 /**
926  * mono_string_hash:
927  * @s: the string to hash
928  *
929  * Returns the hash for the string.
930  */
931 guint
932 mono_string_hash (MonoString *s)
933 {
934         const guint16 *p = mono_string_chars (s);
935         int i, len = mono_string_length (s);
936         guint h = 0;
937
938         for (i = 0; i < len; i++) {
939                 h = (h << 5) - h + *p;
940                 p++;
941         }
942
943         return h;       
944 }
945
946 static gboolean
947 mono_ptrarray_equal (gpointer *s1, gpointer *s2)
948 {
949         int len = GPOINTER_TO_INT (s1 [0]);
950         if (len != GPOINTER_TO_INT (s2 [0]))
951                 return FALSE;
952
953         return memcmp (s1 + 1, s2 + 1, len * sizeof(gpointer)) == 0; 
954 }
955
956 static guint
957 mono_ptrarray_hash (gpointer *s)
958 {
959         int i;
960         int len = GPOINTER_TO_INT (s [0]);
961         guint hash = 0;
962         
963         for (i = 1; i < len; i++)
964                 hash += GPOINTER_TO_UINT (s [i]);
965
966         return hash;    
967 }
968
969 /*
970  * Allocate an id for domain and set domain->domain_id.
971  * LOCKING: must be called while holding appdomains_mutex.
972  * We try to assign low numbers to the domain, so it can be used
973  * as an index in data tables to lookup domain-specific info
974  * with minimal memory overhead. We also try not to reuse the
975  * same id too quickly (to help debugging).
976  */
977 static int
978 domain_id_alloc (MonoDomain *domain)
979 {
980         int id = -1, i;
981         if (!appdomains_list) {
982                 appdomain_list_size = 2;
983                 appdomains_list = mono_gc_alloc_fixed (appdomain_list_size * sizeof (void*), NULL);
984         }
985         for (i = appdomain_next; i < appdomain_list_size; ++i) {
986                 if (!appdomains_list [i]) {
987                         id = i;
988                         break;
989                 }
990         }
991         if (id == -1) {
992                 for (i = 0; i < appdomain_next; ++i) {
993                         if (!appdomains_list [i]) {
994                                 id = i;
995                                 break;
996                         }
997                 }
998         }
999         if (id == -1) {
1000                 MonoDomain **new_list;
1001                 int new_size = appdomain_list_size * 2;
1002                 if (new_size >= (1 << 16))
1003                         g_assert_not_reached ();
1004                 id = appdomain_list_size;
1005                 new_list = mono_gc_alloc_fixed (new_size * sizeof (void*), NULL);
1006                 memcpy (new_list, appdomains_list, appdomain_list_size * sizeof (void*));
1007                 mono_gc_free_fixed (appdomains_list);
1008                 appdomains_list = new_list;
1009                 appdomain_list_size = new_size;
1010         }
1011         domain->domain_id = id;
1012         appdomains_list [id] = domain;
1013         appdomain_next++;
1014         if (appdomain_next > appdomain_list_size)
1015                 appdomain_next = 0;
1016         return id;
1017 }
1018
1019 static guint32 domain_gc_bitmap [sizeof(MonoDomain)/4/32 + 1];
1020 static gpointer domain_gc_desc = NULL;
1021 static guint32 domain_shadow_serial = 0L;
1022
1023 MonoDomain *
1024 mono_domain_create (void)
1025 {
1026         MonoDomain *domain;
1027         guint32 shadow_serial;
1028   
1029         mono_appdomains_lock ();
1030         shadow_serial = domain_shadow_serial++;
1031   
1032         if (!domain_gc_desc) {
1033                 unsigned int i, bit = 0;
1034                 for (i = G_STRUCT_OFFSET (MonoDomain, MONO_DOMAIN_FIRST_OBJECT); i < G_STRUCT_OFFSET (MonoDomain, MONO_DOMAIN_FIRST_GC_TRACKED); i += sizeof (gpointer)) {
1035                         bit = i / sizeof (gpointer);
1036                         domain_gc_bitmap [bit / 32] |= 1 << (bit % 32);
1037                 }
1038                 domain_gc_desc = mono_gc_make_descr_from_bitmap (domain_gc_bitmap, bit + 1);
1039         }
1040         mono_appdomains_unlock ();
1041
1042         domain = mono_gc_alloc_fixed (sizeof (MonoDomain), domain_gc_desc);
1043         domain->shadow_serial = shadow_serial;
1044         domain->domain = NULL;
1045         domain->setup = NULL;
1046         domain->friendly_name = NULL;
1047         domain->search_path = NULL;
1048
1049         domain->mp = mono_mempool_new ();
1050         domain->code_mp = mono_code_manager_new ();
1051         domain->env = mono_g_hash_table_new_type ((GHashFunc)mono_string_hash, (GCompareFunc)mono_string_equal, MONO_HASH_KEY_VALUE_GC);
1052         domain->domain_assemblies = NULL;
1053         domain->class_vtable_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1054         domain->proxy_vtable_hash = g_hash_table_new ((GHashFunc)mono_ptrarray_hash, (GCompareFunc)mono_ptrarray_equal);
1055         domain->static_data_array = NULL;
1056         mono_jit_code_hash_init (&domain->jit_code_hash);
1057         domain->ldstr_table = mono_g_hash_table_new ((GHashFunc)mono_string_hash, (GCompareFunc)mono_string_equal);
1058         domain->jit_info_table = jit_info_table_new ();
1059         domain->class_init_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1060         domain->jump_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1061         domain->finalizable_objects_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1062         domain->jit_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1063         domain->delegate_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1064
1065         InitializeCriticalSection (&domain->lock);
1066         InitializeCriticalSection (&domain->assemblies_lock);
1067
1068         mono_appdomains_lock ();
1069         domain_id_alloc (domain);
1070         mono_appdomains_unlock ();
1071
1072         return domain;
1073 }
1074
1075 /**
1076  * mono_init_internal:
1077  * 
1078  * Creates the initial application domain and initializes the mono_defaults
1079  * structure.
1080  * This function is guaranteed to not run any IL code.
1081  * If exe_filename is not NULL, the method will determine the required runtime
1082  * from the exe configuration file or the version PE field.
1083  * If runtime_version is not NULL, that runtime version will be used.
1084  * Either exe_filename or runtime_version must be provided.
1085  *
1086  * Returns: the initial domain.
1087  */
1088 static MonoDomain *
1089 mono_init_internal (const char *filename, const char *exe_filename, const char *runtime_version)
1090 {
1091         static MonoDomain *domain = NULL;
1092         MonoAssembly *ass = NULL;
1093         MonoImageOpenStatus status = MONO_IMAGE_OK;
1094         const MonoRuntimeInfo* runtimes [G_N_ELEMENTS (supported_runtimes) + 1];
1095         int n;
1096
1097         if (domain)
1098                 g_assert_not_reached ();
1099
1100         MONO_GC_PRE_INIT ();
1101
1102         appdomain_thread_id = TlsAlloc ();
1103
1104         InitializeCriticalSection (&appdomains_mutex);
1105
1106         mono_metadata_init ();
1107         mono_raw_buffer_init ();
1108         mono_images_init ();
1109         mono_assemblies_init ();
1110         mono_classes_init ();
1111         mono_loader_init ();
1112         mono_reflection_init ();
1113
1114         /* FIXME: When should we release this memory? */
1115         MONO_GC_REGISTER_ROOT (appdomains_list);
1116
1117         domain = mono_domain_create ();
1118         mono_root_domain = domain;
1119
1120         SET_APPDOMAIN (domain);
1121         
1122         /* Get a list of runtimes supported by the exe */
1123         if (exe_filename != NULL) {
1124                 get_runtimes_from_exe (exe_filename, runtimes);
1125         } else if (runtime_version != NULL) {
1126                 runtimes [0] = get_runtime_by_version (runtime_version);
1127                 runtimes [1] = NULL;
1128         }
1129
1130         if (runtimes [0] == NULL) {
1131                 const MonoRuntimeInfo *default_runtime = get_runtime_by_version (DEFAULT_RUNTIME_VERSION);
1132                 runtimes [0] = default_runtime;
1133                 runtimes [1] = NULL;
1134                 g_print ("WARNING: The runtime version supported by this application is unavailable.\n");
1135                 g_print ("Using default runtime: %s\n", default_runtime->runtime_version);
1136         }
1137
1138         /* The selected runtime will be the first one for which there is a mscrolib.dll */
1139         for (n = 0; runtimes [n] != NULL && ass == NULL; n++) {
1140                 current_runtime = runtimes [n];
1141                 ass = mono_assembly_load_corlib (current_runtime, &status);
1142                 if (status != MONO_IMAGE_OK && status != MONO_IMAGE_ERROR_ERRNO)
1143                         break;
1144
1145         }
1146
1147         if ((status != MONO_IMAGE_OK) || (ass == NULL)) {
1148                 switch (status){
1149                 case MONO_IMAGE_ERROR_ERRNO: {
1150                         char *corlib_file = g_build_filename (mono_assembly_getrootdir (), "mono", current_runtime->framework_version, "mscorlib.dll", NULL);
1151                         g_print ("The assembly mscorlib.dll was not found or could not be loaded.\n");
1152                         g_print ("It should have been installed in the `%s' directory.\n", corlib_file);
1153                         g_free (corlib_file);
1154                         break;
1155                 }
1156                 case MONO_IMAGE_IMAGE_INVALID:
1157                         g_print ("The file %s/mscorlib.dll is an invalid CIL image\n",
1158                                  mono_assembly_getrootdir ());
1159                         break;
1160                 case MONO_IMAGE_MISSING_ASSEMBLYREF:
1161                         g_print ("Missing assembly reference in %s/mscorlib.dll\n",
1162                                  mono_assembly_getrootdir ());
1163                         break;
1164                 case MONO_IMAGE_OK:
1165                         /* to suppress compiler warning */
1166                         break;
1167                 }
1168                 
1169                 exit (1);
1170         }
1171         mono_defaults.corlib = mono_assembly_get_image (ass);
1172
1173         mono_defaults.object_class = mono_class_from_name (
1174                 mono_defaults.corlib, "System", "Object");
1175         g_assert (mono_defaults.object_class != 0);
1176
1177         mono_defaults.void_class = mono_class_from_name (
1178                 mono_defaults.corlib, "System", "Void");
1179         g_assert (mono_defaults.void_class != 0);
1180
1181         mono_defaults.boolean_class = mono_class_from_name (
1182                 mono_defaults.corlib, "System", "Boolean");
1183         g_assert (mono_defaults.boolean_class != 0);
1184
1185         mono_defaults.byte_class = mono_class_from_name (
1186                 mono_defaults.corlib, "System", "Byte");
1187         g_assert (mono_defaults.byte_class != 0);
1188
1189         mono_defaults.sbyte_class = mono_class_from_name (
1190                 mono_defaults.corlib, "System", "SByte");
1191         g_assert (mono_defaults.sbyte_class != 0);
1192
1193         mono_defaults.int16_class = mono_class_from_name (
1194                 mono_defaults.corlib, "System", "Int16");
1195         g_assert (mono_defaults.int16_class != 0);
1196
1197         mono_defaults.uint16_class = mono_class_from_name (
1198                 mono_defaults.corlib, "System", "UInt16");
1199         g_assert (mono_defaults.uint16_class != 0);
1200
1201         mono_defaults.int32_class = mono_class_from_name (
1202                 mono_defaults.corlib, "System", "Int32");
1203         g_assert (mono_defaults.int32_class != 0);
1204
1205         mono_defaults.uint32_class = mono_class_from_name (
1206                 mono_defaults.corlib, "System", "UInt32");
1207         g_assert (mono_defaults.uint32_class != 0);
1208
1209         mono_defaults.uint_class = mono_class_from_name (
1210                 mono_defaults.corlib, "System", "UIntPtr");
1211         g_assert (mono_defaults.uint_class != 0);
1212
1213         mono_defaults.int_class = mono_class_from_name (
1214                 mono_defaults.corlib, "System", "IntPtr");
1215         g_assert (mono_defaults.int_class != 0);
1216
1217         mono_defaults.int64_class = mono_class_from_name (
1218                 mono_defaults.corlib, "System", "Int64");
1219         g_assert (mono_defaults.int64_class != 0);
1220
1221         mono_defaults.uint64_class = mono_class_from_name (
1222                 mono_defaults.corlib, "System", "UInt64");
1223         g_assert (mono_defaults.uint64_class != 0);
1224
1225         mono_defaults.single_class = mono_class_from_name (
1226                 mono_defaults.corlib, "System", "Single");
1227         g_assert (mono_defaults.single_class != 0);
1228
1229         mono_defaults.double_class = mono_class_from_name (
1230                 mono_defaults.corlib, "System", "Double");
1231         g_assert (mono_defaults.double_class != 0);
1232
1233         mono_defaults.char_class = mono_class_from_name (
1234                 mono_defaults.corlib, "System", "Char");
1235         g_assert (mono_defaults.char_class != 0);
1236
1237         mono_defaults.string_class = mono_class_from_name (
1238                 mono_defaults.corlib, "System", "String");
1239         g_assert (mono_defaults.string_class != 0);
1240
1241         mono_defaults.enum_class = mono_class_from_name (
1242                 mono_defaults.corlib, "System", "Enum");
1243         g_assert (mono_defaults.enum_class != 0);
1244
1245         mono_defaults.array_class = mono_class_from_name (
1246                 mono_defaults.corlib, "System", "Array");
1247         g_assert (mono_defaults.array_class != 0);
1248
1249         mono_defaults.delegate_class = mono_class_from_name (
1250                 mono_defaults.corlib, "System", "Delegate");
1251         g_assert (mono_defaults.delegate_class != 0 );
1252
1253         mono_defaults.multicastdelegate_class = mono_class_from_name (
1254                 mono_defaults.corlib, "System", "MulticastDelegate");
1255         g_assert (mono_defaults.multicastdelegate_class != 0 );
1256
1257         mono_defaults.asyncresult_class = mono_class_from_name (
1258                 mono_defaults.corlib, "System.Runtime.Remoting.Messaging", 
1259                 "AsyncResult");
1260         g_assert (mono_defaults.asyncresult_class != 0 );
1261
1262         mono_defaults.waithandle_class = mono_class_from_name (
1263                 mono_defaults.corlib, "System.Threading", "WaitHandle");
1264         g_assert (mono_defaults.waithandle_class != 0 );
1265
1266         mono_defaults.typehandle_class = mono_class_from_name (
1267                 mono_defaults.corlib, "System", "RuntimeTypeHandle");
1268         g_assert (mono_defaults.typehandle_class != 0);
1269
1270         mono_defaults.methodhandle_class = mono_class_from_name (
1271                 mono_defaults.corlib, "System", "RuntimeMethodHandle");
1272         g_assert (mono_defaults.methodhandle_class != 0);
1273
1274         mono_defaults.fieldhandle_class = mono_class_from_name (
1275                 mono_defaults.corlib, "System", "RuntimeFieldHandle");
1276         g_assert (mono_defaults.fieldhandle_class != 0);
1277
1278         mono_defaults.systemtype_class = mono_class_from_name (
1279                 mono_defaults.corlib, "System", "Type");
1280         g_assert (mono_defaults.systemtype_class != 0);
1281
1282         mono_defaults.monotype_class = mono_class_from_name (
1283                 mono_defaults.corlib, "System", "MonoType");
1284         g_assert (mono_defaults.monotype_class != 0);
1285
1286         mono_defaults.exception_class = mono_class_from_name (
1287                 mono_defaults.corlib, "System", "Exception");
1288         g_assert (mono_defaults.exception_class != 0);
1289
1290         mono_defaults.threadabortexception_class = mono_class_from_name (
1291                 mono_defaults.corlib, "System.Threading", "ThreadAbortException");
1292         g_assert (mono_defaults.threadabortexception_class != 0);
1293
1294         mono_defaults.thread_class = mono_class_from_name (
1295                 mono_defaults.corlib, "System.Threading", "Thread");
1296         g_assert (mono_defaults.thread_class != 0);
1297
1298         mono_defaults.appdomain_class = mono_class_from_name (
1299                 mono_defaults.corlib, "System", "AppDomain");
1300         g_assert (mono_defaults.appdomain_class != 0);
1301
1302         mono_defaults.transparent_proxy_class = mono_class_from_name (
1303                 mono_defaults.corlib, "System.Runtime.Remoting.Proxies", "TransparentProxy");
1304         g_assert (mono_defaults.transparent_proxy_class != 0);
1305
1306         mono_defaults.real_proxy_class = mono_class_from_name (
1307                 mono_defaults.corlib, "System.Runtime.Remoting.Proxies", "RealProxy");
1308         g_assert (mono_defaults.real_proxy_class != 0);
1309
1310         mono_defaults.mono_method_message_class = mono_class_from_name (
1311                 mono_defaults.corlib, "System.Runtime.Remoting.Messaging", "MonoMethodMessage");
1312         g_assert (mono_defaults.mono_method_message_class != 0);
1313
1314         mono_defaults.field_info_class = mono_class_from_name (
1315                 mono_defaults.corlib, "System.Reflection", "FieldInfo");
1316         g_assert (mono_defaults.field_info_class != 0);
1317
1318         mono_defaults.method_info_class = mono_class_from_name (
1319                 mono_defaults.corlib, "System.Reflection", "MethodInfo");
1320         g_assert (mono_defaults.method_info_class != 0);
1321
1322         mono_defaults.stringbuilder_class = mono_class_from_name (
1323                 mono_defaults.corlib, "System.Text", "StringBuilder");
1324         g_assert (mono_defaults.stringbuilder_class != 0);
1325
1326         mono_defaults.math_class = mono_class_from_name (
1327                 mono_defaults.corlib, "System", "Math");
1328         g_assert (mono_defaults.math_class != 0);
1329
1330         mono_defaults.stack_frame_class = mono_class_from_name (
1331                 mono_defaults.corlib, "System.Diagnostics", "StackFrame");
1332         g_assert (mono_defaults.stack_frame_class != 0);
1333
1334         mono_defaults.stack_trace_class = mono_class_from_name (
1335                 mono_defaults.corlib, "System.Diagnostics", "StackTrace");
1336         g_assert (mono_defaults.stack_trace_class != 0);
1337
1338         mono_defaults.marshal_class = mono_class_from_name (
1339                 mono_defaults.corlib, "System.Runtime.InteropServices", "Marshal");
1340         g_assert (mono_defaults.marshal_class != 0);
1341
1342         mono_defaults.iserializeable_class = mono_class_from_name (
1343                 mono_defaults.corlib, "System.Runtime.Serialization", "ISerializable");
1344         g_assert (mono_defaults.iserializeable_class != 0);
1345
1346         mono_defaults.serializationinfo_class = mono_class_from_name (
1347                 mono_defaults.corlib, "System.Runtime.Serialization", "SerializationInfo");
1348         g_assert (mono_defaults.serializationinfo_class != 0);
1349
1350         mono_defaults.streamingcontext_class = mono_class_from_name (
1351                 mono_defaults.corlib, "System.Runtime.Serialization", "StreamingContext");
1352         g_assert (mono_defaults.streamingcontext_class != 0);
1353
1354         mono_defaults.typed_reference_class =  mono_class_from_name (
1355                 mono_defaults.corlib, "System", "TypedReference");
1356         g_assert (mono_defaults.typed_reference_class != 0);
1357
1358         mono_defaults.argumenthandle_class =  mono_class_from_name (
1359                 mono_defaults.corlib, "System", "RuntimeArgumentHandle");
1360         g_assert (mono_defaults.argumenthandle_class != 0);
1361
1362         mono_defaults.marshalbyrefobject_class =  mono_class_from_name (
1363                 mono_defaults.corlib, "System", "MarshalByRefObject");
1364         g_assert (mono_defaults.marshalbyrefobject_class != 0);
1365
1366         mono_defaults.monitor_class =  mono_class_from_name (
1367                 mono_defaults.corlib, "System.Threading", "Monitor");
1368         g_assert (mono_defaults.monitor_class != 0);
1369
1370         mono_defaults.iremotingtypeinfo_class = mono_class_from_name (
1371                 mono_defaults.corlib, "System.Runtime.Remoting", "IRemotingTypeInfo");
1372         g_assert (mono_defaults.iremotingtypeinfo_class != 0);
1373
1374         mono_defaults.runtimesecurityframe_class = mono_class_from_name (
1375                 mono_defaults.corlib, "System.Security", "RuntimeSecurityFrame");
1376
1377         mono_defaults.executioncontext_class = mono_class_from_name (
1378                 mono_defaults.corlib, "System.Threading", "ExecutionContext");
1379
1380         mono_defaults.internals_visible_class = mono_class_from_name (
1381                 mono_defaults.corlib, "System.Runtime.CompilerServices", "InternalsVisibleToAttribute");
1382
1383         /*
1384          * mscorlib needs a little help, only now it can load its friends list (after we have
1385          * loaded the InternalsVisibleToAttribute), load it now
1386          */
1387         mono_assembly_load_friends (ass);
1388         
1389         mono_defaults.safehandle_class = mono_class_from_name (
1390                 mono_defaults.corlib, "System.Runtime.InteropServices", "SafeHandle");
1391
1392         mono_defaults.handleref_class = mono_class_from_name (
1393                 mono_defaults.corlib, "System.Runtime.InteropServices", "HandleRef");
1394
1395         mono_defaults.attribute_class = mono_class_from_name (
1396                 mono_defaults.corlib, "System", "Attribute");
1397
1398         mono_defaults.customattribute_data_class = mono_class_from_name (
1399                 mono_defaults.corlib, "System.Reflection", "CustomAttributeData");
1400
1401         /* these are initialized lazily when COM features are used */
1402         mono_defaults.variant_class = NULL;
1403         mono_defaults.com_object_class = NULL;
1404         mono_defaults.com_interop_proxy_class = NULL;
1405         mono_defaults.iunknown_class = NULL;
1406         mono_defaults.idispatch_class = NULL;
1407
1408         /*
1409          * Note that mono_defaults.generic_*_class is only non-NULL if we're
1410          * using the 2.0 corlib.
1411          */
1412         mono_class_init (mono_defaults.array_class);
1413         mono_defaults.generic_nullable_class = mono_class_from_name (
1414                 mono_defaults.corlib, "System", "Nullable`1");
1415         mono_defaults.generic_ilist_class = mono_class_from_name (
1416                 mono_defaults.corlib, "System.Collections.Generic", "IList`1");
1417
1418         domain->friendly_name = g_path_get_basename (filename);
1419
1420         return domain;
1421 }
1422
1423 /**
1424  * mono_init:
1425  * 
1426  * Creates the initial application domain and initializes the mono_defaults
1427  * structure.
1428  * This function is guaranteed to not run any IL code.
1429  * The runtime is initialized using the default runtime version.
1430  *
1431  * Returns: the initial domain.
1432  */
1433 MonoDomain *
1434 mono_init (const char *domain_name)
1435 {
1436         return mono_init_internal (domain_name, NULL, DEFAULT_RUNTIME_VERSION);
1437 }
1438
1439 /**
1440  * mono_init_from_assembly:
1441  * 
1442  * Creates the initial application domain and initializes the mono_defaults
1443  * structure.
1444  * This function is guaranteed to not run any IL code.
1445  * The runtime is initialized using the runtime version required by the
1446  * provided executable. The version is determined by looking at the exe 
1447  * configuration file and the version PE field)
1448  *
1449  * Returns: the initial domain.
1450  */
1451 MonoDomain *
1452 mono_init_from_assembly (const char *domain_name, const char *filename)
1453 {
1454         return mono_init_internal (domain_name, filename, NULL);
1455 }
1456
1457 /**
1458  * mono_init_version:
1459  * 
1460  * Creates the initial application domain and initializes the mono_defaults
1461  * structure.
1462  * This function is guaranteed to not run any IL code.
1463  * The runtime is initialized using the provided rutime version.
1464  *
1465  * Returns: the initial domain.
1466  */
1467 MonoDomain *
1468 mono_init_version (const char *domain_name, const char *version)
1469 {
1470         return mono_init_internal (domain_name, NULL, version);
1471 }
1472
1473 /**
1474  * mono_init_com_types:
1475  *
1476  * Initializes all types needed for COM Interop in mono_defaults structure. 
1477  */
1478 void 
1479 mono_init_com_types (void)
1480 {
1481         static gboolean initialized = FALSE;
1482
1483         if (initialized)
1484                 return;
1485         
1486         /* FIXME: do I need some threading protection here */
1487
1488         g_assert (mono_defaults.corlib);
1489
1490         mono_defaults.variant_class = mono_class_from_name (
1491                 mono_defaults.corlib, "System", "Variant");
1492         g_assert (mono_defaults.variant_class != 0);
1493
1494         mono_defaults.com_object_class = mono_class_from_name (
1495                 mono_defaults.corlib, "System", "__ComObject");
1496         g_assert (mono_defaults.com_object_class != 0);
1497
1498         mono_defaults.com_interop_proxy_class = mono_class_from_name (
1499                 mono_defaults.corlib, "Mono.Interop", "ComInteropProxy");
1500         g_assert (mono_defaults.com_interop_proxy_class != 0);
1501
1502         mono_defaults.iunknown_class = mono_class_from_name (
1503                 mono_defaults.corlib, "Mono.Interop", "IUnknown");
1504         g_assert (mono_defaults.iunknown_class != 0);
1505
1506         mono_defaults.idispatch_class = mono_class_from_name (
1507                 mono_defaults.corlib, "Mono.Interop", "IDispatch");
1508         g_assert (mono_defaults.idispatch_class != 0);
1509
1510         initialized = TRUE;
1511 }
1512
1513 /**
1514  * mono_cleanup:
1515  *
1516  * Cleans up all metadata modules. 
1517  */
1518 void
1519 mono_cleanup (void)
1520 {
1521         mono_loader_cleanup ();
1522         mono_classes_cleanup ();
1523         mono_assemblies_cleanup ();
1524         mono_images_cleanup ();
1525         mono_raw_buffer_cleanup ();
1526         mono_metadata_cleanup ();
1527
1528         TlsFree (appdomain_thread_id);
1529         DeleteCriticalSection (&appdomains_mutex);
1530 }
1531
1532 /**
1533  * mono_get_root_domain:
1534  *
1535  * The root AppDomain is the initial domain created by the runtime when it is
1536  * initialized.  Programs execute on this AppDomain, but can create new ones
1537  * later.   Currently there is no unmanaged API to create new AppDomains, this
1538  * must be done from managed code.
1539  *
1540  * Returns: the root appdomain, to obtain the current domain, use mono_domain_get ()
1541  */
1542 MonoDomain*
1543 mono_get_root_domain (void)
1544 {
1545         return mono_root_domain;
1546 }
1547
1548 /**
1549  * mono_domain_get:
1550  *
1551  * Returns: the current domain, to obtain the root domain use
1552  * mono_get_root_domain().
1553  */
1554 MonoDomain *
1555 mono_domain_get ()
1556 {
1557         return GET_APPDOMAIN ();
1558 }
1559
1560 /**
1561  * mono_domain_set_internal:
1562  * @domain: the new domain
1563  *
1564  * Sets the current domain to @domain.
1565  */
1566 void
1567 mono_domain_set_internal (MonoDomain *domain)
1568 {
1569         SET_APPDOMAIN (domain);
1570         SET_APPCONTEXT (domain->default_context);
1571 }
1572
1573 void
1574 mono_domain_foreach (MonoDomainFunc func, gpointer user_data)
1575 {
1576         int i, size;
1577         MonoDomain **copy;
1578
1579         /*
1580          * Create a copy of the data to avoid calling the user callback
1581          * inside the lock because that could lead to deadlocks.
1582          * We can do this because this function is not perf. critical.
1583          */
1584         mono_appdomains_lock ();
1585         size = appdomain_list_size;
1586         copy = mono_gc_alloc_fixed (appdomain_list_size * sizeof (void*), NULL);
1587         memcpy (copy, appdomains_list, appdomain_list_size * sizeof (void*));
1588         mono_appdomains_unlock ();
1589
1590         for (i = 0; i < size; ++i) {
1591                 if (copy [i])
1592                         func (copy [i], user_data);
1593         }
1594
1595         mono_gc_free_fixed (copy);
1596 }
1597
1598 /**
1599  * mono_domain_assembly_open:
1600  * @domain: the application domain
1601  * @name: file name of the assembly
1602  *
1603  * fixme: maybe we should integrate this with mono_assembly_open ??
1604  */
1605 MonoAssembly *
1606 mono_domain_assembly_open (MonoDomain *domain, const char *name)
1607 {
1608         MonoAssembly *ass;
1609         GSList *tmp;
1610
1611         mono_domain_assemblies_lock (domain);
1612         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1613                 ass = tmp->data;
1614                 if (strcmp (name, ass->aname.name) == 0) {
1615                         mono_domain_assemblies_unlock (domain);
1616                         return ass;
1617                 }
1618         }
1619         mono_domain_assemblies_unlock (domain);
1620
1621         if (!(ass = mono_assembly_open (name, NULL)))
1622                 return NULL;
1623
1624         return ass;
1625 }
1626
1627 static void
1628 dynamic_method_info_free (gpointer key, gpointer value, gpointer user_data)
1629 {
1630         MonoJitDynamicMethodInfo *di = value;
1631         mono_code_manager_destroy (di->code_mp);
1632         g_free (di);
1633 }
1634
1635 static void
1636 delete_jump_list (gpointer key, gpointer value, gpointer user_data)
1637 {
1638         g_slist_free (value);
1639 }
1640
1641 void
1642 mono_domain_free (MonoDomain *domain, gboolean force)
1643 {
1644         GSList *tmp;
1645         if ((domain == mono_root_domain) && !force) {
1646                 g_warning ("cant unload root domain");
1647                 return;
1648         }
1649
1650         mono_debugger_event (MONO_DEBUGGER_EVENT_DOMAIN_UNLOAD, domain->domain_id, 0);
1651
1652         mono_appdomains_lock ();
1653         appdomains_list [domain->domain_id] = NULL;
1654         mono_appdomains_unlock ();
1655
1656         /* FIXME: free delegate_hash_table when it's used */
1657         if (domain->search_path) {
1658                 g_strfreev (domain->search_path);
1659                 domain->search_path = NULL;
1660         }
1661         domain->create_proxy_for_type_method = NULL;
1662         domain->private_invoke_method = NULL;
1663         domain->default_context = NULL;
1664         domain->out_of_memory_ex = NULL;
1665         domain->null_reference_ex = NULL;
1666         domain->stack_overflow_ex = NULL;
1667         domain->entry_assembly = NULL;
1668         /* must do this early as it accesses fields and types */
1669         if (domain->special_static_fields) {
1670                 mono_alloc_special_static_data_free (domain->special_static_fields);
1671                 g_hash_table_destroy (domain->special_static_fields);
1672                 domain->special_static_fields = NULL;
1673         }
1674         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1675                 MonoAssembly *ass = tmp->data;
1676                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading domain %s %p, assembly %s %p, refcount=%d\n", domain->friendly_name, domain, ass->aname.name, ass, ass->ref_count);
1677                 mono_assembly_close (ass);
1678         }
1679         g_slist_free (domain->domain_assemblies);
1680         domain->domain_assemblies = NULL;
1681
1682         g_free (domain->friendly_name);
1683         domain->friendly_name = NULL;
1684         mono_g_hash_table_destroy (domain->env);
1685         domain->env = NULL;
1686         g_hash_table_destroy (domain->class_vtable_hash);
1687         domain->class_vtable_hash = NULL;
1688         g_hash_table_destroy (domain->proxy_vtable_hash);
1689         domain->proxy_vtable_hash = NULL;
1690         if (domain->static_data_array) {
1691                 mono_gc_free_fixed (domain->static_data_array);
1692                 domain->static_data_array = NULL;
1693         }
1694         mono_internal_hash_table_destroy (&domain->jit_code_hash);
1695         if (domain->dynamic_code_hash) {
1696                 g_hash_table_foreach (domain->dynamic_code_hash, dynamic_method_info_free, NULL);
1697                 g_hash_table_destroy (domain->dynamic_code_hash);
1698                 domain->dynamic_code_hash = NULL;
1699         }
1700         mono_g_hash_table_destroy (domain->ldstr_table);
1701         domain->ldstr_table = NULL;
1702         jit_info_table_free (domain->jit_info_table);
1703         domain->jit_info_table = NULL;
1704 #ifdef DEBUG_DOMAIN_UNLOAD
1705         mono_mempool_invalidate (domain->mp);
1706         mono_code_manager_invalidate (domain->code_mp);
1707 #else
1708         mono_mempool_destroy (domain->mp);
1709         domain->mp = NULL;
1710         mono_code_manager_destroy (domain->code_mp);
1711         domain->code_mp = NULL;
1712 #endif  
1713         if (domain->jump_target_hash) {
1714                 g_hash_table_foreach (domain->jump_target_hash, delete_jump_list, NULL);
1715                 g_hash_table_destroy (domain->jump_target_hash);
1716                 domain->jump_target_hash = NULL;
1717         }
1718         if (domain->type_hash) {
1719                 mono_g_hash_table_destroy (domain->type_hash);
1720                 domain->type_hash = NULL;
1721         }
1722         if (domain->refobject_hash) {
1723                 mono_g_hash_table_destroy (domain->refobject_hash);
1724                 domain->refobject_hash = NULL;
1725         }
1726         if (domain->type_init_exception_hash) {
1727                 mono_g_hash_table_destroy (domain->type_init_exception_hash);
1728                 domain->type_init_exception_hash = NULL;
1729         }
1730         g_hash_table_destroy (domain->class_init_trampoline_hash);
1731         domain->class_init_trampoline_hash = NULL;
1732         g_hash_table_destroy (domain->jump_trampoline_hash);
1733         domain->jump_trampoline_hash = NULL;
1734         g_hash_table_destroy (domain->finalizable_objects_hash);
1735         domain->finalizable_objects_hash = NULL;
1736         g_hash_table_destroy (domain->jit_trampoline_hash);
1737         domain->jit_trampoline_hash = NULL;
1738         g_hash_table_destroy (domain->delegate_trampoline_hash);
1739         domain->delegate_trampoline_hash = NULL;
1740         if (domain->delegate_invoke_impl_with_target_hash) {
1741                 g_hash_table_destroy (domain->delegate_invoke_impl_with_target_hash);
1742                 domain->delegate_invoke_impl_with_target_hash = NULL;
1743         }
1744         if (domain->delegate_invoke_impl_no_target_hash) {
1745                 g_hash_table_destroy (domain->delegate_invoke_impl_no_target_hash);
1746                 domain->delegate_invoke_impl_no_target_hash = NULL;
1747         }
1748         DeleteCriticalSection (&domain->assemblies_lock);
1749         DeleteCriticalSection (&domain->lock);
1750         domain->setup = NULL;
1751
1752         /* FIXME: anything else required ? */
1753
1754         mono_gc_free_fixed (domain);
1755
1756         if ((domain == mono_root_domain))
1757                 mono_root_domain = NULL;
1758 }
1759
1760 /**
1761  * mono_domain_get_id:
1762  * @domainid: the ID
1763  *
1764  * Returns: the a domain for a specific domain id.
1765  */
1766 MonoDomain * 
1767 mono_domain_get_by_id (gint32 domainid) 
1768 {
1769         MonoDomain * domain;
1770
1771         mono_appdomains_lock ();
1772         if (domainid < appdomain_list_size)
1773                 domain = appdomains_list [domainid];
1774         else
1775                 domain = NULL;
1776         mono_appdomains_unlock ();
1777
1778         return domain;
1779 }
1780
1781 gint32
1782 mono_domain_get_id (MonoDomain *domain)
1783 {
1784         return domain->domain_id;
1785 }
1786
1787 void 
1788 mono_context_set (MonoAppContext * new_context)
1789 {
1790         SET_APPCONTEXT (new_context);
1791 }
1792
1793 MonoAppContext * 
1794 mono_context_get (void)
1795 {
1796         return GET_APPCONTEXT ();
1797 }
1798
1799 /* LOCKING: the caller holds the lock for this domain */
1800 void
1801 mono_domain_add_class_static_data (MonoDomain *domain, MonoClass *klass, gpointer data, guint32 *bitmap)
1802 {
1803         /* The first entry in the array is the index of the next free slot
1804          * and the total size of the array
1805          */
1806         int next;
1807         if (domain->static_data_array) {
1808                 int size = GPOINTER_TO_INT (domain->static_data_array [1]);
1809                 next = GPOINTER_TO_INT (domain->static_data_array [0]);
1810                 if (next >= size) {
1811                         gpointer *new_array = mono_gc_alloc_fixed (sizeof (gpointer) * (size * 2), NULL);
1812                         memcpy (new_array, domain->static_data_array, sizeof (gpointer) * size);
1813                         size *= 2;
1814                         new_array [1] = GINT_TO_POINTER (size);
1815                         mono_gc_free_fixed (domain->static_data_array);
1816                         domain->static_data_array = new_array;
1817                 }
1818         } else {
1819                 int size = 32;
1820                 gpointer *new_array = mono_gc_alloc_fixed (sizeof (gpointer) * size, NULL);
1821                 next = 2;
1822                 new_array [0] = GINT_TO_POINTER (next);
1823                 new_array [1] = GINT_TO_POINTER (size);
1824                 domain->static_data_array = new_array;
1825         }
1826         domain->static_data_array [next++] = data;
1827         domain->static_data_array [0] = GINT_TO_POINTER (next);
1828 }
1829
1830 MonoImage*
1831 mono_get_corlib (void)
1832 {
1833         return mono_defaults.corlib;
1834 }
1835
1836 MonoClass*
1837 mono_get_object_class (void)
1838 {
1839         return mono_defaults.object_class;
1840 }
1841
1842 MonoClass*
1843 mono_get_byte_class (void)
1844 {
1845         return mono_defaults.byte_class;
1846 }
1847
1848 MonoClass*
1849 mono_get_void_class (void)
1850 {
1851         return mono_defaults.void_class;
1852 }
1853
1854 MonoClass*
1855 mono_get_boolean_class (void)
1856 {
1857         return mono_defaults.boolean_class;
1858 }
1859
1860 MonoClass*
1861 mono_get_sbyte_class (void)
1862 {
1863         return mono_defaults.sbyte_class;
1864 }
1865
1866 MonoClass*
1867 mono_get_int16_class (void)
1868 {
1869         return mono_defaults.int16_class;
1870 }
1871
1872 MonoClass*
1873 mono_get_uint16_class (void)
1874 {
1875         return mono_defaults.uint16_class;
1876 }
1877
1878 MonoClass*
1879 mono_get_int32_class (void)
1880 {
1881         return mono_defaults.int32_class;
1882 }
1883
1884 MonoClass*
1885 mono_get_uint32_class (void)
1886 {
1887         return mono_defaults.uint32_class;
1888 }
1889
1890 MonoClass*
1891 mono_get_intptr_class (void)
1892 {
1893         return mono_defaults.int_class;
1894 }
1895
1896 MonoClass*
1897 mono_get_uintptr_class (void)
1898 {
1899         return mono_defaults.uint_class;
1900 }
1901
1902 MonoClass*
1903 mono_get_int64_class (void)
1904 {
1905         return mono_defaults.int64_class;
1906 }
1907
1908 MonoClass*
1909 mono_get_uint64_class (void)
1910 {
1911         return mono_defaults.uint64_class;
1912 }
1913
1914 MonoClass*
1915 mono_get_single_class (void)
1916 {
1917         return mono_defaults.single_class;
1918 }
1919
1920 MonoClass*
1921 mono_get_double_class (void)
1922 {
1923         return mono_defaults.double_class;
1924 }
1925
1926 MonoClass*
1927 mono_get_char_class (void)
1928 {
1929         return mono_defaults.char_class;
1930 }
1931
1932 MonoClass*
1933 mono_get_string_class (void)
1934 {
1935         return mono_defaults.string_class;
1936 }
1937
1938 MonoClass*
1939 mono_get_enum_class (void)
1940 {
1941         return mono_defaults.enum_class;
1942 }
1943
1944 MonoClass*
1945 mono_get_array_class (void)
1946 {
1947         return mono_defaults.array_class;
1948 }
1949
1950 MonoClass*
1951 mono_get_thread_class (void)
1952 {
1953         return mono_defaults.thread_class;
1954 }
1955
1956 MonoClass*
1957 mono_get_exception_class (void)
1958 {
1959         return mono_defaults.exception_class;
1960 }
1961
1962
1963 static char* get_attribute_value (const gchar **attribute_names, 
1964                                         const gchar **attribute_values, 
1965                                         const char *att_name)
1966 {
1967         int n;
1968         for (n=0; attribute_names[n] != NULL; n++) {
1969                 if (strcmp (attribute_names[n], att_name) == 0)
1970                         return g_strdup (attribute_values[n]);
1971         }
1972         return NULL;
1973 }
1974
1975 static void start_element (GMarkupParseContext *context, 
1976                            const gchar         *element_name,
1977                            const gchar        **attribute_names,
1978                            const gchar        **attribute_values,
1979                            gpointer             user_data,
1980                            GError             **error)
1981 {
1982         AppConfigInfo* app_config = (AppConfigInfo*) user_data;
1983         
1984         if (strcmp (element_name, "configuration") == 0) {
1985                 app_config->configuration_count++;
1986                 return;
1987         }
1988         if (strcmp (element_name, "startup") == 0) {
1989                 app_config->startup_count++;
1990                 return;
1991         }
1992         
1993         if (app_config->configuration_count != 1 || app_config->startup_count != 1)
1994                 return;
1995         
1996         if (strcmp (element_name, "requiredRuntime") == 0) {
1997                 app_config->required_runtime = get_attribute_value (attribute_names, attribute_values, "version");
1998         } else if (strcmp (element_name, "supportedRuntime") == 0) {
1999                 char *version = get_attribute_value (attribute_names, attribute_values, "version");
2000                 app_config->supported_runtimes = g_slist_append (app_config->supported_runtimes, version);
2001         }
2002 }
2003
2004 static void end_element   (GMarkupParseContext *context,
2005                            const gchar         *element_name,
2006                            gpointer             user_data,
2007                            GError             **error)
2008 {
2009         AppConfigInfo* app_config = (AppConfigInfo*) user_data;
2010         
2011         if (strcmp (element_name, "configuration") == 0) {
2012                 app_config->configuration_count--;
2013         } else if (strcmp (element_name, "startup") == 0) {
2014                 app_config->startup_count--;
2015         }
2016 }
2017
2018 static const GMarkupParser 
2019 mono_parser = {
2020         start_element,
2021         end_element,
2022         NULL,
2023         NULL,
2024         NULL
2025 };
2026
2027 static AppConfigInfo *
2028 app_config_parse (const char *exe_filename)
2029 {
2030         AppConfigInfo *app_config;
2031         GMarkupParseContext *context;
2032         char *text;
2033         gsize len;
2034         struct stat buf;
2035         const char *bundled_config;
2036         char *config_filename;
2037
2038         bundled_config = mono_config_string_for_assembly_file (exe_filename);
2039
2040         if (bundled_config) {
2041                 text = g_strdup (bundled_config);
2042                 len = strlen (text);
2043         } else {
2044                 config_filename = g_strconcat (exe_filename, ".config", NULL);
2045
2046                 if (stat (config_filename, &buf) != 0) {
2047                         g_free (config_filename);
2048                         return NULL;
2049                 }
2050         
2051                 if (!g_file_get_contents (config_filename, &text, &len, NULL)) {
2052                         g_free (config_filename);
2053                         return NULL;
2054                 }
2055                 g_free (config_filename);
2056         }
2057
2058         app_config = g_new0 (AppConfigInfo, 1);
2059
2060         context = g_markup_parse_context_new (&mono_parser, 0, app_config, NULL);
2061         if (g_markup_parse_context_parse (context, text, len, NULL)) {
2062                 g_markup_parse_context_end_parse (context, NULL);
2063         }
2064         g_markup_parse_context_free (context);
2065         g_free (text);
2066         return app_config;
2067 }
2068
2069 static void 
2070 app_config_free (AppConfigInfo* app_config)
2071 {
2072         char *rt;
2073         GSList *list = app_config->supported_runtimes;
2074         while (list != NULL) {
2075                 rt = (char*)list->data;
2076                 g_free (rt);
2077                 list = g_slist_next (list);
2078         }
2079         g_slist_free (app_config->supported_runtimes);
2080         g_free (app_config->required_runtime);
2081         g_free (app_config);
2082 }
2083
2084
2085 static const MonoRuntimeInfo*
2086 get_runtime_by_version (const char *version)
2087 {
2088         int n;
2089         int max = G_N_ELEMENTS (supported_runtimes);
2090         
2091         for (n=0; n<max; n++) {
2092                 if (strcmp (version, supported_runtimes[n].runtime_version) == 0)
2093                         return &supported_runtimes[n];
2094         }
2095         return NULL;
2096 }
2097
2098 static void
2099 get_runtimes_from_exe (const char *exe_file, const MonoRuntimeInfo** runtimes)
2100 {
2101         AppConfigInfo* app_config;
2102         char *version;
2103         const MonoRuntimeInfo* runtime = NULL;
2104         MonoImage *image = NULL;
2105         
2106         app_config = app_config_parse (exe_file);
2107         
2108         if (app_config != NULL) {
2109                 /* Check supportedRuntime elements, if none is supported, fail.
2110                  * If there are no such elements, look for a requiredRuntime element.
2111                  */
2112                 if (app_config->supported_runtimes != NULL) {
2113                         int n = 0;
2114                         GSList *list = app_config->supported_runtimes;
2115                         while (list != NULL) {
2116                                 version = (char*) list->data;
2117                                 runtime = get_runtime_by_version (version);
2118                                 if (runtime != NULL)
2119                                         runtimes [n++] = runtime;
2120                                 list = g_slist_next (list);
2121                         }
2122                         runtimes [n] = NULL;
2123                         app_config_free (app_config);
2124                         return;
2125                 }
2126                 
2127                 /* Check the requiredRuntime element. This is for 1.0 apps only. */
2128                 if (app_config->required_runtime != NULL) {
2129                         runtimes [0] = get_runtime_by_version (app_config->required_runtime);
2130                         runtimes [1] = NULL;
2131                         app_config_free (app_config);
2132                         return;
2133                 }
2134                 app_config_free (app_config);
2135         }
2136         
2137         /* Look for a runtime with the exact version */
2138         image = mono_assembly_open_from_bundle (exe_file, NULL, FALSE);
2139
2140         if (image == NULL)
2141                 image = mono_image_open (exe_file, NULL);
2142
2143         if (image == NULL) {
2144                 /* The image is wrong or the file was not found. In this case return
2145                  * a default runtime and leave to the initialization method the work of
2146                  * reporting the error.
2147                  */
2148                 runtimes [0] = get_runtime_by_version (DEFAULT_RUNTIME_VERSION);
2149                 runtimes [1] = NULL;
2150                 return;
2151         }
2152
2153         /* 
2154          * FIXME: This would cause us to unload the image, and it will be loaded again later.
2155          * Disabling it will mean the initial exe will not be unloaded on shutdown.
2156          */
2157         //mono_image_close (image);
2158
2159         runtimes [0] = get_runtime_by_version (image->version);
2160         runtimes [1] = NULL;
2161 }
2162
2163
2164 /**
2165  * mono_get_runtime_info:
2166  *
2167  * Returns: the version of the current runtime instance.
2168  */
2169 const MonoRuntimeInfo*
2170 mono_get_runtime_info (void)
2171 {
2172         return current_runtime;
2173 }
2174
2175 gchar *
2176 mono_debugger_check_runtime_version (const char *filename)
2177 {
2178         const MonoRuntimeInfo* runtimes [G_N_ELEMENTS (supported_runtimes) + 1];
2179         const MonoRuntimeInfo *rinfo;
2180
2181         get_runtimes_from_exe (filename, runtimes);
2182         rinfo = runtimes [0];
2183
2184         if (!rinfo)
2185                 return g_strdup_printf ("Cannot get runtime version from assembly `%s'", filename);
2186
2187         if (rinfo != current_runtime)
2188                 return g_strdup_printf ("The Mono Debugger is currently using the `%s' runtime, but "
2189                                         "the assembly `%s' requires version `%s'", current_runtime->runtime_version,
2190                                         filename, rinfo->runtime_version);
2191
2192         return NULL;
2193 }