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