2007-12-29 Zoltan Varga <vargaz@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/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/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,1,0,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 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 /*
915  * mono_jit_info_get_generic_sharing_context:
916  * @ji: a jit info
917  *
918  * Returns the jit info's generic sharing context, or NULL if it
919  * doesn't have one.
920  */
921 MonoGenericSharingContext*
922 mono_jit_info_get_generic_sharing_context (MonoJitInfo *ji)
923 {
924         if (ji->has_generic_sharing_context)
925                 return *((MonoGenericSharingContext**)&ji->clauses [ji->num_clauses]);
926         else
927                 return NULL;
928 }
929
930 /*
931  * mono_jit_info_set_generic_sharing_context:
932  * @ji: a jit info
933  * @gsctx: a generic sharing context
934  *
935  * Sets the jit info's generic sharing context.  The jit info must
936  * have memory allocated for the context.
937  */
938 void
939 mono_jit_info_set_generic_sharing_context (MonoJitInfo *ji, MonoGenericSharingContext *gsctx)
940 {
941         g_assert (ji->has_generic_sharing_context);
942
943         *((MonoGenericSharingContext**)&ji->clauses [ji->num_clauses]) = gsctx;
944 }
945
946 /**
947  * mono_string_equal:
948  * @s1: First string to compare
949  * @s2: Second string to compare
950  *
951  * Returns FALSE if the strings differ.
952  */
953 gboolean
954 mono_string_equal (MonoString *s1, MonoString *s2)
955 {
956         int l1 = mono_string_length (s1);
957         int l2 = mono_string_length (s2);
958
959         if (s1 == s2)
960                 return TRUE;
961         if (l1 != l2)
962                 return FALSE;
963
964         return memcmp (mono_string_chars (s1), mono_string_chars (s2), l1 * 2) == 0; 
965 }
966
967 /**
968  * mono_string_hash:
969  * @s: the string to hash
970  *
971  * Returns the hash for the string.
972  */
973 guint
974 mono_string_hash (MonoString *s)
975 {
976         const guint16 *p = mono_string_chars (s);
977         int i, len = mono_string_length (s);
978         guint h = 0;
979
980         for (i = 0; i < len; i++) {
981                 h = (h << 5) - h + *p;
982                 p++;
983         }
984
985         return h;       
986 }
987
988 static gboolean
989 mono_ptrarray_equal (gpointer *s1, gpointer *s2)
990 {
991         int len = GPOINTER_TO_INT (s1 [0]);
992         if (len != GPOINTER_TO_INT (s2 [0]))
993                 return FALSE;
994
995         return memcmp (s1 + 1, s2 + 1, len * sizeof(gpointer)) == 0; 
996 }
997
998 static guint
999 mono_ptrarray_hash (gpointer *s)
1000 {
1001         int i;
1002         int len = GPOINTER_TO_INT (s [0]);
1003         guint hash = 0;
1004         
1005         for (i = 1; i < len; i++)
1006                 hash += GPOINTER_TO_UINT (s [i]);
1007
1008         return hash;    
1009 }
1010
1011 /*
1012  * Allocate an id for domain and set domain->domain_id.
1013  * LOCKING: must be called while holding appdomains_mutex.
1014  * We try to assign low numbers to the domain, so it can be used
1015  * as an index in data tables to lookup domain-specific info
1016  * with minimal memory overhead. We also try not to reuse the
1017  * same id too quickly (to help debugging).
1018  */
1019 static int
1020 domain_id_alloc (MonoDomain *domain)
1021 {
1022         int id = -1, i;
1023         if (!appdomains_list) {
1024                 appdomain_list_size = 2;
1025                 appdomains_list = mono_gc_alloc_fixed (appdomain_list_size * sizeof (void*), NULL);
1026         }
1027         for (i = appdomain_next; i < appdomain_list_size; ++i) {
1028                 if (!appdomains_list [i]) {
1029                         id = i;
1030                         break;
1031                 }
1032         }
1033         if (id == -1) {
1034                 for (i = 0; i < appdomain_next; ++i) {
1035                         if (!appdomains_list [i]) {
1036                                 id = i;
1037                                 break;
1038                         }
1039                 }
1040         }
1041         if (id == -1) {
1042                 MonoDomain **new_list;
1043                 int new_size = appdomain_list_size * 2;
1044                 if (new_size >= (1 << 16))
1045                         g_assert_not_reached ();
1046                 id = appdomain_list_size;
1047                 new_list = mono_gc_alloc_fixed (new_size * sizeof (void*), NULL);
1048                 memcpy (new_list, appdomains_list, appdomain_list_size * sizeof (void*));
1049                 mono_gc_free_fixed (appdomains_list);
1050                 appdomains_list = new_list;
1051                 appdomain_list_size = new_size;
1052         }
1053         domain->domain_id = id;
1054         appdomains_list [id] = domain;
1055         appdomain_next++;
1056         if (appdomain_next > appdomain_list_size)
1057                 appdomain_next = 0;
1058         return id;
1059 }
1060
1061 static guint32 domain_gc_bitmap [sizeof(MonoDomain)/4/32 + 1];
1062 static gpointer domain_gc_desc = NULL;
1063 static guint32 domain_shadow_serial = 0L;
1064
1065 MonoDomain *
1066 mono_domain_create (void)
1067 {
1068         MonoDomain *domain;
1069         guint32 shadow_serial;
1070   
1071         mono_appdomains_lock ();
1072         shadow_serial = domain_shadow_serial++;
1073   
1074         if (!domain_gc_desc) {
1075                 unsigned int i, bit = 0;
1076                 for (i = G_STRUCT_OFFSET (MonoDomain, MONO_DOMAIN_FIRST_OBJECT); i < G_STRUCT_OFFSET (MonoDomain, MONO_DOMAIN_FIRST_GC_TRACKED); i += sizeof (gpointer)) {
1077                         bit = i / sizeof (gpointer);
1078                         domain_gc_bitmap [bit / 32] |= 1 << (bit % 32);
1079                 }
1080                 domain_gc_desc = mono_gc_make_descr_from_bitmap (domain_gc_bitmap, bit + 1);
1081         }
1082         mono_appdomains_unlock ();
1083
1084         domain = mono_gc_alloc_fixed (sizeof (MonoDomain), domain_gc_desc);
1085         domain->shadow_serial = shadow_serial;
1086         domain->domain = NULL;
1087         domain->setup = NULL;
1088         domain->friendly_name = NULL;
1089         domain->search_path = NULL;
1090
1091         mono_profiler_appdomain_event (domain, MONO_PROFILE_START_LOAD);
1092
1093         domain->mp = mono_mempool_new ();
1094         domain->code_mp = mono_code_manager_new ();
1095         domain->env = mono_g_hash_table_new_type ((GHashFunc)mono_string_hash, (GCompareFunc)mono_string_equal, MONO_HASH_KEY_VALUE_GC);
1096         domain->domain_assemblies = NULL;
1097         domain->class_vtable_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1098         domain->proxy_vtable_hash = g_hash_table_new ((GHashFunc)mono_ptrarray_hash, (GCompareFunc)mono_ptrarray_equal);
1099         domain->static_data_array = NULL;
1100         mono_jit_code_hash_init (&domain->jit_code_hash);
1101         domain->ldstr_table = mono_g_hash_table_new ((GHashFunc)mono_string_hash, (GCompareFunc)mono_string_equal);
1102         domain->jit_info_table = jit_info_table_new ();
1103         domain->class_init_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1104         domain->jump_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1105         domain->finalizable_objects_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1106         domain->jit_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1107         domain->delegate_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1108
1109         InitializeCriticalSection (&domain->lock);
1110         InitializeCriticalSection (&domain->assemblies_lock);
1111
1112         domain->shared_generics_hash = NULL;
1113
1114         mono_debug_domain_create (domain);
1115
1116         mono_appdomains_lock ();
1117         domain_id_alloc (domain);
1118         mono_appdomains_unlock ();
1119
1120         mono_profiler_appdomain_loaded (domain, MONO_PROFILE_OK);
1121         
1122         return domain;
1123 }
1124
1125 /**
1126  * mono_init_internal:
1127  * 
1128  * Creates the initial application domain and initializes the mono_defaults
1129  * structure.
1130  * This function is guaranteed to not run any IL code.
1131  * If exe_filename is not NULL, the method will determine the required runtime
1132  * from the exe configuration file or the version PE field.
1133  * If runtime_version is not NULL, that runtime version will be used.
1134  * Either exe_filename or runtime_version must be provided.
1135  *
1136  * Returns: the initial domain.
1137  */
1138 static MonoDomain *
1139 mono_init_internal (const char *filename, const char *exe_filename, const char *runtime_version)
1140 {
1141         static MonoDomain *domain = NULL;
1142         MonoAssembly *ass = NULL;
1143         MonoImageOpenStatus status = MONO_IMAGE_OK;
1144         const MonoRuntimeInfo* runtimes [G_N_ELEMENTS (supported_runtimes) + 1];
1145         int n;
1146
1147         if (domain)
1148                 g_assert_not_reached ();
1149
1150         mono_counters_register ("Max native code in a domain", MONO_COUNTER_INT|MONO_COUNTER_JIT, &max_domain_code_size);
1151         mono_counters_register ("Max code space allocated in a domain", MONO_COUNTER_INT|MONO_COUNTER_JIT, &max_domain_code_alloc);
1152         mono_counters_register ("Total code space allocated", MONO_COUNTER_INT|MONO_COUNTER_JIT, &total_domain_code_alloc);
1153
1154         mono_gc_base_init ();
1155
1156         appdomain_thread_id = TlsAlloc ();
1157
1158         InitializeCriticalSection (&appdomains_mutex);
1159
1160         mono_metadata_init ();
1161         mono_raw_buffer_init ();
1162         mono_images_init ();
1163         mono_assemblies_init ();
1164         mono_classes_init ();
1165         mono_loader_init ();
1166         mono_reflection_init ();
1167
1168         /* FIXME: When should we release this memory? */
1169         MONO_GC_REGISTER_ROOT (appdomains_list);
1170
1171         domain = mono_domain_create ();
1172         mono_root_domain = domain;
1173
1174         SET_APPDOMAIN (domain);
1175         
1176         /* Get a list of runtimes supported by the exe */
1177         if (exe_filename != NULL) {
1178                 /*
1179                  * This function will load the exe file as a MonoImage. We need to close it, but
1180                  * that would mean it would be reloaded later. So instead, we save it to
1181                  * exe_image, and close it during shutdown.
1182                  */
1183                 get_runtimes_from_exe (exe_filename, &exe_image, runtimes);
1184         } else if (runtime_version != NULL) {
1185                 runtimes [0] = get_runtime_by_version (runtime_version);
1186                 runtimes [1] = NULL;
1187         }
1188
1189         if (runtimes [0] == NULL) {
1190                 const MonoRuntimeInfo *default_runtime = get_runtime_by_version (DEFAULT_RUNTIME_VERSION);
1191                 runtimes [0] = default_runtime;
1192                 runtimes [1] = NULL;
1193                 g_print ("WARNING: The runtime version supported by this application is unavailable.\n");
1194                 g_print ("Using default runtime: %s\n", default_runtime->runtime_version);
1195         }
1196
1197         /* The selected runtime will be the first one for which there is a mscrolib.dll */
1198         for (n = 0; runtimes [n] != NULL && ass == NULL; n++) {
1199                 current_runtime = runtimes [n];
1200                 ass = mono_assembly_load_corlib (current_runtime, &status);
1201                 if (status != MONO_IMAGE_OK && status != MONO_IMAGE_ERROR_ERRNO)
1202                         break;
1203
1204         }
1205         
1206         /* Now that we have a runtime, set the policy for unhandled exceptions */
1207         if (mono_get_runtime_info ()->framework_version [0] < '2') {
1208                 mono_runtime_unhandled_exception_policy_set (MONO_UNHANLED_POLICY_LEGACY);
1209         }
1210
1211         if ((status != MONO_IMAGE_OK) || (ass == NULL)) {
1212                 switch (status){
1213                 case MONO_IMAGE_ERROR_ERRNO: {
1214                         char *corlib_file = g_build_filename (mono_assembly_getrootdir (), "mono", current_runtime->framework_version, "mscorlib.dll", NULL);
1215                         g_print ("The assembly mscorlib.dll was not found or could not be loaded.\n");
1216                         g_print ("It should have been installed in the `%s' directory.\n", corlib_file);
1217                         g_free (corlib_file);
1218                         break;
1219                 }
1220                 case MONO_IMAGE_IMAGE_INVALID:
1221                         g_print ("The file %s/mscorlib.dll is an invalid CIL image\n",
1222                                  mono_assembly_getrootdir ());
1223                         break;
1224                 case MONO_IMAGE_MISSING_ASSEMBLYREF:
1225                         g_print ("Missing assembly reference in %s/mscorlib.dll\n",
1226                                  mono_assembly_getrootdir ());
1227                         break;
1228                 case MONO_IMAGE_OK:
1229                         /* to suppress compiler warning */
1230                         break;
1231                 }
1232                 
1233                 exit (1);
1234         }
1235         mono_defaults.corlib = mono_assembly_get_image (ass);
1236
1237         mono_defaults.object_class = mono_class_from_name (
1238                 mono_defaults.corlib, "System", "Object");
1239         g_assert (mono_defaults.object_class != 0);
1240
1241         mono_defaults.void_class = mono_class_from_name (
1242                 mono_defaults.corlib, "System", "Void");
1243         g_assert (mono_defaults.void_class != 0);
1244
1245         mono_defaults.boolean_class = mono_class_from_name (
1246                 mono_defaults.corlib, "System", "Boolean");
1247         g_assert (mono_defaults.boolean_class != 0);
1248
1249         mono_defaults.byte_class = mono_class_from_name (
1250                 mono_defaults.corlib, "System", "Byte");
1251         g_assert (mono_defaults.byte_class != 0);
1252
1253         mono_defaults.sbyte_class = mono_class_from_name (
1254                 mono_defaults.corlib, "System", "SByte");
1255         g_assert (mono_defaults.sbyte_class != 0);
1256
1257         mono_defaults.int16_class = mono_class_from_name (
1258                 mono_defaults.corlib, "System", "Int16");
1259         g_assert (mono_defaults.int16_class != 0);
1260
1261         mono_defaults.uint16_class = mono_class_from_name (
1262                 mono_defaults.corlib, "System", "UInt16");
1263         g_assert (mono_defaults.uint16_class != 0);
1264
1265         mono_defaults.int32_class = mono_class_from_name (
1266                 mono_defaults.corlib, "System", "Int32");
1267         g_assert (mono_defaults.int32_class != 0);
1268
1269         mono_defaults.uint32_class = mono_class_from_name (
1270                 mono_defaults.corlib, "System", "UInt32");
1271         g_assert (mono_defaults.uint32_class != 0);
1272
1273         mono_defaults.uint_class = mono_class_from_name (
1274                 mono_defaults.corlib, "System", "UIntPtr");
1275         g_assert (mono_defaults.uint_class != 0);
1276
1277         mono_defaults.int_class = mono_class_from_name (
1278                 mono_defaults.corlib, "System", "IntPtr");
1279         g_assert (mono_defaults.int_class != 0);
1280
1281         mono_defaults.int64_class = mono_class_from_name (
1282                 mono_defaults.corlib, "System", "Int64");
1283         g_assert (mono_defaults.int64_class != 0);
1284
1285         mono_defaults.uint64_class = mono_class_from_name (
1286                 mono_defaults.corlib, "System", "UInt64");
1287         g_assert (mono_defaults.uint64_class != 0);
1288
1289         mono_defaults.single_class = mono_class_from_name (
1290                 mono_defaults.corlib, "System", "Single");
1291         g_assert (mono_defaults.single_class != 0);
1292
1293         mono_defaults.double_class = mono_class_from_name (
1294                 mono_defaults.corlib, "System", "Double");
1295         g_assert (mono_defaults.double_class != 0);
1296
1297         mono_defaults.char_class = mono_class_from_name (
1298                 mono_defaults.corlib, "System", "Char");
1299         g_assert (mono_defaults.char_class != 0);
1300
1301         mono_defaults.string_class = mono_class_from_name (
1302                 mono_defaults.corlib, "System", "String");
1303         g_assert (mono_defaults.string_class != 0);
1304
1305         mono_defaults.enum_class = mono_class_from_name (
1306                 mono_defaults.corlib, "System", "Enum");
1307         g_assert (mono_defaults.enum_class != 0);
1308
1309         mono_defaults.array_class = mono_class_from_name (
1310                 mono_defaults.corlib, "System", "Array");
1311         g_assert (mono_defaults.array_class != 0);
1312
1313         mono_defaults.delegate_class = mono_class_from_name (
1314                 mono_defaults.corlib, "System", "Delegate");
1315         g_assert (mono_defaults.delegate_class != 0 );
1316
1317         mono_defaults.multicastdelegate_class = mono_class_from_name (
1318                 mono_defaults.corlib, "System", "MulticastDelegate");
1319         g_assert (mono_defaults.multicastdelegate_class != 0 );
1320
1321         mono_defaults.asyncresult_class = mono_class_from_name (
1322                 mono_defaults.corlib, "System.Runtime.Remoting.Messaging", 
1323                 "AsyncResult");
1324         g_assert (mono_defaults.asyncresult_class != 0 );
1325
1326         mono_defaults.waithandle_class = mono_class_from_name (
1327                 mono_defaults.corlib, "System.Threading", "WaitHandle");
1328         g_assert (mono_defaults.waithandle_class != 0 );
1329
1330         mono_defaults.typehandle_class = mono_class_from_name (
1331                 mono_defaults.corlib, "System", "RuntimeTypeHandle");
1332         g_assert (mono_defaults.typehandle_class != 0);
1333
1334         mono_defaults.methodhandle_class = mono_class_from_name (
1335                 mono_defaults.corlib, "System", "RuntimeMethodHandle");
1336         g_assert (mono_defaults.methodhandle_class != 0);
1337
1338         mono_defaults.fieldhandle_class = mono_class_from_name (
1339                 mono_defaults.corlib, "System", "RuntimeFieldHandle");
1340         g_assert (mono_defaults.fieldhandle_class != 0);
1341
1342         mono_defaults.systemtype_class = mono_class_from_name (
1343                 mono_defaults.corlib, "System", "Type");
1344         g_assert (mono_defaults.systemtype_class != 0);
1345
1346         mono_defaults.monotype_class = mono_class_from_name (
1347                 mono_defaults.corlib, "System", "MonoType");
1348         g_assert (mono_defaults.monotype_class != 0);
1349
1350         mono_defaults.exception_class = mono_class_from_name (
1351                 mono_defaults.corlib, "System", "Exception");
1352         g_assert (mono_defaults.exception_class != 0);
1353
1354         mono_defaults.threadabortexception_class = mono_class_from_name (
1355                 mono_defaults.corlib, "System.Threading", "ThreadAbortException");
1356         g_assert (mono_defaults.threadabortexception_class != 0);
1357
1358         mono_defaults.thread_class = mono_class_from_name (
1359                 mono_defaults.corlib, "System.Threading", "Thread");
1360         g_assert (mono_defaults.thread_class != 0);
1361
1362         mono_defaults.appdomain_class = mono_class_from_name (
1363                 mono_defaults.corlib, "System", "AppDomain");
1364         g_assert (mono_defaults.appdomain_class != 0);
1365
1366         mono_defaults.transparent_proxy_class = mono_class_from_name (
1367                 mono_defaults.corlib, "System.Runtime.Remoting.Proxies", "TransparentProxy");
1368         g_assert (mono_defaults.transparent_proxy_class != 0);
1369
1370         mono_defaults.real_proxy_class = mono_class_from_name (
1371                 mono_defaults.corlib, "System.Runtime.Remoting.Proxies", "RealProxy");
1372         g_assert (mono_defaults.real_proxy_class != 0);
1373
1374         mono_defaults.mono_method_message_class = mono_class_from_name (
1375                 mono_defaults.corlib, "System.Runtime.Remoting.Messaging", "MonoMethodMessage");
1376         g_assert (mono_defaults.mono_method_message_class != 0);
1377
1378         mono_defaults.field_info_class = mono_class_from_name (
1379                 mono_defaults.corlib, "System.Reflection", "FieldInfo");
1380         g_assert (mono_defaults.field_info_class != 0);
1381
1382         mono_defaults.method_info_class = mono_class_from_name (
1383                 mono_defaults.corlib, "System.Reflection", "MethodInfo");
1384         g_assert (mono_defaults.method_info_class != 0);
1385
1386         mono_defaults.stringbuilder_class = mono_class_from_name (
1387                 mono_defaults.corlib, "System.Text", "StringBuilder");
1388         g_assert (mono_defaults.stringbuilder_class != 0);
1389
1390         mono_defaults.math_class = mono_class_from_name (
1391                 mono_defaults.corlib, "System", "Math");
1392         g_assert (mono_defaults.math_class != 0);
1393
1394         mono_defaults.stack_frame_class = mono_class_from_name (
1395                 mono_defaults.corlib, "System.Diagnostics", "StackFrame");
1396         g_assert (mono_defaults.stack_frame_class != 0);
1397
1398         mono_defaults.stack_trace_class = mono_class_from_name (
1399                 mono_defaults.corlib, "System.Diagnostics", "StackTrace");
1400         g_assert (mono_defaults.stack_trace_class != 0);
1401
1402         mono_defaults.marshal_class = mono_class_from_name (
1403                 mono_defaults.corlib, "System.Runtime.InteropServices", "Marshal");
1404         g_assert (mono_defaults.marshal_class != 0);
1405
1406         mono_defaults.iserializeable_class = mono_class_from_name (
1407                 mono_defaults.corlib, "System.Runtime.Serialization", "ISerializable");
1408         g_assert (mono_defaults.iserializeable_class != 0);
1409
1410         mono_defaults.serializationinfo_class = mono_class_from_name (
1411                 mono_defaults.corlib, "System.Runtime.Serialization", "SerializationInfo");
1412         g_assert (mono_defaults.serializationinfo_class != 0);
1413
1414         mono_defaults.streamingcontext_class = mono_class_from_name (
1415                 mono_defaults.corlib, "System.Runtime.Serialization", "StreamingContext");
1416         g_assert (mono_defaults.streamingcontext_class != 0);
1417
1418         mono_defaults.typed_reference_class =  mono_class_from_name (
1419                 mono_defaults.corlib, "System", "TypedReference");
1420         g_assert (mono_defaults.typed_reference_class != 0);
1421
1422         mono_defaults.argumenthandle_class =  mono_class_from_name (
1423                 mono_defaults.corlib, "System", "RuntimeArgumentHandle");
1424         g_assert (mono_defaults.argumenthandle_class != 0);
1425
1426         mono_defaults.marshalbyrefobject_class =  mono_class_from_name (
1427                 mono_defaults.corlib, "System", "MarshalByRefObject");
1428         g_assert (mono_defaults.marshalbyrefobject_class != 0);
1429
1430         mono_defaults.monitor_class =  mono_class_from_name (
1431                 mono_defaults.corlib, "System.Threading", "Monitor");
1432         g_assert (mono_defaults.monitor_class != 0);
1433
1434         mono_defaults.iremotingtypeinfo_class = mono_class_from_name (
1435                 mono_defaults.corlib, "System.Runtime.Remoting", "IRemotingTypeInfo");
1436         g_assert (mono_defaults.iremotingtypeinfo_class != 0);
1437
1438         mono_defaults.runtimesecurityframe_class = mono_class_from_name (
1439                 mono_defaults.corlib, "System.Security", "RuntimeSecurityFrame");
1440
1441         mono_defaults.executioncontext_class = mono_class_from_name (
1442                 mono_defaults.corlib, "System.Threading", "ExecutionContext");
1443
1444         mono_defaults.internals_visible_class = mono_class_from_name (
1445                 mono_defaults.corlib, "System.Runtime.CompilerServices", "InternalsVisibleToAttribute");
1446
1447         /*
1448          * mscorlib needs a little help, only now it can load its friends list (after we have
1449          * loaded the InternalsVisibleToAttribute), load it now
1450          */
1451         mono_assembly_load_friends (ass);
1452         
1453         mono_defaults.safehandle_class = mono_class_from_name (
1454                 mono_defaults.corlib, "System.Runtime.InteropServices", "SafeHandle");
1455
1456         mono_defaults.handleref_class = mono_class_from_name (
1457                 mono_defaults.corlib, "System.Runtime.InteropServices", "HandleRef");
1458
1459         mono_defaults.attribute_class = mono_class_from_name (
1460                 mono_defaults.corlib, "System", "Attribute");
1461
1462         mono_defaults.customattribute_data_class = mono_class_from_name (
1463                 mono_defaults.corlib, "System.Reflection", "CustomAttributeData");
1464
1465         /* these are initialized lazily when COM features are used */
1466         mono_defaults.variant_class = NULL;
1467         mono_defaults.com_object_class = NULL;
1468         mono_defaults.com_interop_proxy_class = NULL;
1469         mono_defaults.iunknown_class = NULL;
1470         mono_defaults.idispatch_class = NULL;
1471
1472         /*
1473          * Note that mono_defaults.generic_*_class is only non-NULL if we're
1474          * using the 2.0 corlib.
1475          */
1476         mono_class_init (mono_defaults.array_class);
1477         mono_defaults.generic_nullable_class = mono_class_from_name (
1478                 mono_defaults.corlib, "System", "Nullable`1");
1479         mono_defaults.generic_ilist_class = mono_class_from_name (
1480                 mono_defaults.corlib, "System.Collections.Generic", "IList`1");
1481
1482         domain->friendly_name = g_path_get_basename (filename);
1483
1484         _mono_debug_init_corlib (domain);
1485
1486         return domain;
1487 }
1488
1489 /**
1490  * mono_init:
1491  * 
1492  * Creates the initial application domain and initializes the mono_defaults
1493  * structure.
1494  * This function is guaranteed to not run any IL code.
1495  * The runtime is initialized using the default runtime version.
1496  *
1497  * Returns: the initial domain.
1498  */
1499 MonoDomain *
1500 mono_init (const char *domain_name)
1501 {
1502         return mono_init_internal (domain_name, NULL, DEFAULT_RUNTIME_VERSION);
1503 }
1504
1505 /**
1506  * mono_init_from_assembly:
1507  * 
1508  * Creates the initial application domain and initializes the mono_defaults
1509  * structure.
1510  * This function is guaranteed to not run any IL code.
1511  * The runtime is initialized using the runtime version required by the
1512  * provided executable. The version is determined by looking at the exe 
1513  * configuration file and the version PE field)
1514  *
1515  * Returns: the initial domain.
1516  */
1517 MonoDomain *
1518 mono_init_from_assembly (const char *domain_name, const char *filename)
1519 {
1520         return mono_init_internal (domain_name, filename, NULL);
1521 }
1522
1523 /**
1524  * mono_init_version:
1525  * 
1526  * Creates the initial application domain and initializes the mono_defaults
1527  * structure.
1528  * This function is guaranteed to not run any IL code.
1529  * The runtime is initialized using the provided rutime version.
1530  *
1531  * Returns: the initial domain.
1532  */
1533 MonoDomain *
1534 mono_init_version (const char *domain_name, const char *version)
1535 {
1536         return mono_init_internal (domain_name, NULL, version);
1537 }
1538
1539 /**
1540  * mono_init_com_types:
1541  *
1542  * Initializes all types needed for COM Interop in mono_defaults structure. 
1543  */
1544 void 
1545 mono_init_com_types (void)
1546 {
1547         static gboolean initialized = FALSE;
1548
1549         if (initialized)
1550                 return;
1551         
1552         /* FIXME: do I need some threading protection here */
1553
1554         g_assert (mono_defaults.corlib);
1555
1556         mono_defaults.variant_class = mono_class_from_name (
1557                 mono_defaults.corlib, "System", "Variant");
1558         g_assert (mono_defaults.variant_class != 0);
1559
1560         mono_defaults.com_object_class = mono_class_from_name (
1561                 mono_defaults.corlib, "System", "__ComObject");
1562         g_assert (mono_defaults.com_object_class != 0);
1563
1564         mono_defaults.com_interop_proxy_class = mono_class_from_name (
1565                 mono_defaults.corlib, "Mono.Interop", "ComInteropProxy");
1566         g_assert (mono_defaults.com_interop_proxy_class != 0);
1567
1568         mono_defaults.iunknown_class = mono_class_from_name (
1569                 mono_defaults.corlib, "Mono.Interop", "IUnknown");
1570         g_assert (mono_defaults.iunknown_class != 0);
1571
1572         mono_defaults.idispatch_class = mono_class_from_name (
1573                 mono_defaults.corlib, "Mono.Interop", "IDispatch");
1574         g_assert (mono_defaults.idispatch_class != 0);
1575
1576         initialized = TRUE;
1577 }
1578
1579 /**
1580  * mono_cleanup:
1581  *
1582  * Cleans up all metadata modules. 
1583  */
1584 void
1585 mono_cleanup (void)
1586 {
1587         if (exe_image)
1588                 mono_image_close (exe_image);
1589
1590         mono_loader_cleanup ();
1591         mono_classes_cleanup ();
1592         mono_assemblies_cleanup ();
1593         mono_images_cleanup ();
1594         mono_debug_cleanup ();
1595         mono_raw_buffer_cleanup ();
1596         mono_metadata_cleanup ();
1597
1598         TlsFree (appdomain_thread_id);
1599         DeleteCriticalSection (&appdomains_mutex);
1600 }
1601
1602 /**
1603  * mono_get_root_domain:
1604  *
1605  * The root AppDomain is the initial domain created by the runtime when it is
1606  * initialized.  Programs execute on this AppDomain, but can create new ones
1607  * later.   Currently there is no unmanaged API to create new AppDomains, this
1608  * must be done from managed code.
1609  *
1610  * Returns: the root appdomain, to obtain the current domain, use mono_domain_get ()
1611  */
1612 MonoDomain*
1613 mono_get_root_domain (void)
1614 {
1615         return mono_root_domain;
1616 }
1617
1618 /**
1619  * mono_domain_get:
1620  *
1621  * Returns: the current domain, to obtain the root domain use
1622  * mono_get_root_domain().
1623  */
1624 MonoDomain *
1625 mono_domain_get ()
1626 {
1627         return GET_APPDOMAIN ();
1628 }
1629
1630 /**
1631  * mono_domain_set_internal:
1632  * @domain: the new domain
1633  *
1634  * Sets the current domain to @domain.
1635  */
1636 void
1637 mono_domain_set_internal (MonoDomain *domain)
1638 {
1639         SET_APPDOMAIN (domain);
1640         SET_APPCONTEXT (domain->default_context);
1641 }
1642
1643 void
1644 mono_domain_foreach (MonoDomainFunc func, gpointer user_data)
1645 {
1646         int i, size;
1647         MonoDomain **copy;
1648
1649         /*
1650          * Create a copy of the data to avoid calling the user callback
1651          * inside the lock because that could lead to deadlocks.
1652          * We can do this because this function is not perf. critical.
1653          */
1654         mono_appdomains_lock ();
1655         size = appdomain_list_size;
1656         copy = mono_gc_alloc_fixed (appdomain_list_size * sizeof (void*), NULL);
1657         memcpy (copy, appdomains_list, appdomain_list_size * sizeof (void*));
1658         mono_appdomains_unlock ();
1659
1660         for (i = 0; i < size; ++i) {
1661                 if (copy [i])
1662                         func (copy [i], user_data);
1663         }
1664
1665         mono_gc_free_fixed (copy);
1666 }
1667
1668 /**
1669  * mono_domain_assembly_open:
1670  * @domain: the application domain
1671  * @name: file name of the assembly
1672  *
1673  * fixme: maybe we should integrate this with mono_assembly_open ??
1674  */
1675 MonoAssembly *
1676 mono_domain_assembly_open (MonoDomain *domain, const char *name)
1677 {
1678         MonoAssembly *ass;
1679         GSList *tmp;
1680
1681         mono_domain_assemblies_lock (domain);
1682         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1683                 ass = tmp->data;
1684                 if (strcmp (name, ass->aname.name) == 0) {
1685                         mono_domain_assemblies_unlock (domain);
1686                         return ass;
1687                 }
1688         }
1689         mono_domain_assemblies_unlock (domain);
1690
1691         if (!(ass = mono_assembly_open (name, NULL)))
1692                 return NULL;
1693
1694         return ass;
1695 }
1696
1697 MonoJitInfo*
1698 mono_domain_lookup_shared_generic (MonoDomain *domain, MonoMethod *method)
1699 {
1700         if (!domain->shared_generics_hash)
1701                 return NULL;
1702
1703         return g_hash_table_lookup (domain->shared_generics_hash, method);
1704 }
1705
1706 void
1707 mono_domain_register_shared_generic (MonoDomain *domain, MonoMethod *method, MonoJitInfo *jit_info)
1708 {
1709         if (!domain->shared_generics_hash)
1710                 domain->shared_generics_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1711
1712         g_assert (domain->shared_generics_hash);
1713
1714         g_hash_table_insert (domain->shared_generics_hash, method, jit_info);
1715 }
1716
1717 static void
1718 dynamic_method_info_free (gpointer key, gpointer value, gpointer user_data)
1719 {
1720         MonoJitDynamicMethodInfo *di = value;
1721         mono_code_manager_destroy (di->code_mp);
1722         g_free (di);
1723 }
1724
1725 static void
1726 delete_jump_list (gpointer key, gpointer value, gpointer user_data)
1727 {
1728         g_slist_free (value);
1729 }
1730
1731 void
1732 mono_domain_free (MonoDomain *domain, gboolean force)
1733 {
1734         int code_size, code_alloc;
1735         GSList *tmp;
1736         if ((domain == mono_root_domain) && !force) {
1737                 g_warning ("cant unload root domain");
1738                 return;
1739         }
1740
1741         mono_profiler_appdomain_event (domain, MONO_PROFILE_START_UNLOAD);
1742
1743         mono_debug_domain_unload (domain);
1744
1745         mono_appdomains_lock ();
1746         appdomains_list [domain->domain_id] = NULL;
1747         mono_appdomains_unlock ();
1748
1749         /* FIXME: free delegate_hash_table when it's used */
1750         if (domain->search_path) {
1751                 g_strfreev (domain->search_path);
1752                 domain->search_path = NULL;
1753         }
1754         domain->create_proxy_for_type_method = NULL;
1755         domain->private_invoke_method = NULL;
1756         domain->default_context = NULL;
1757         domain->out_of_memory_ex = NULL;
1758         domain->null_reference_ex = NULL;
1759         domain->stack_overflow_ex = NULL;
1760         domain->entry_assembly = NULL;
1761         /* must do this early as it accesses fields and types */
1762         if (domain->special_static_fields) {
1763                 mono_alloc_special_static_data_free (domain->special_static_fields);
1764                 g_hash_table_destroy (domain->special_static_fields);
1765                 domain->special_static_fields = NULL;
1766         }
1767         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1768                 MonoAssembly *ass = tmp->data;
1769                 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);
1770                 mono_assembly_close (ass);
1771         }
1772         g_slist_free (domain->domain_assemblies);
1773         domain->domain_assemblies = NULL;
1774
1775         g_free (domain->friendly_name);
1776         domain->friendly_name = NULL;
1777         mono_g_hash_table_destroy (domain->env);
1778         domain->env = NULL;
1779         g_hash_table_destroy (domain->class_vtable_hash);
1780         domain->class_vtable_hash = NULL;
1781         g_hash_table_destroy (domain->proxy_vtable_hash);
1782         domain->proxy_vtable_hash = NULL;
1783         if (domain->static_data_array) {
1784                 mono_gc_free_fixed (domain->static_data_array);
1785                 domain->static_data_array = NULL;
1786         }
1787         mono_internal_hash_table_destroy (&domain->jit_code_hash);
1788         if (domain->dynamic_code_hash) {
1789                 g_hash_table_foreach (domain->dynamic_code_hash, dynamic_method_info_free, NULL);
1790                 g_hash_table_destroy (domain->dynamic_code_hash);
1791                 domain->dynamic_code_hash = NULL;
1792         }
1793         mono_g_hash_table_destroy (domain->ldstr_table);
1794         domain->ldstr_table = NULL;
1795         jit_info_table_free (domain->jit_info_table);
1796         domain->jit_info_table = NULL;
1797
1798         /* collect statistics */
1799         code_alloc = mono_code_manager_size (domain->code_mp, &code_size);
1800         total_domain_code_alloc += code_alloc;
1801         max_domain_code_alloc = MAX (max_domain_code_alloc, code_alloc);
1802         max_domain_code_size = MAX (max_domain_code_size, code_size);
1803
1804 #ifdef DEBUG_DOMAIN_UNLOAD
1805         mono_mempool_invalidate (domain->mp);
1806         mono_code_manager_invalidate (domain->code_mp);
1807 #else
1808         mono_mempool_destroy (domain->mp);
1809         domain->mp = NULL;
1810         mono_code_manager_destroy (domain->code_mp);
1811         domain->code_mp = NULL;
1812 #endif  
1813         if (domain->jump_target_hash) {
1814                 g_hash_table_foreach (domain->jump_target_hash, delete_jump_list, NULL);
1815                 g_hash_table_destroy (domain->jump_target_hash);
1816                 domain->jump_target_hash = NULL;
1817         }
1818         if (domain->type_hash) {
1819                 mono_g_hash_table_destroy (domain->type_hash);
1820                 domain->type_hash = NULL;
1821         }
1822         if (domain->refobject_hash) {
1823                 mono_g_hash_table_destroy (domain->refobject_hash);
1824                 domain->refobject_hash = NULL;
1825         }
1826         if (domain->type_init_exception_hash) {
1827                 mono_g_hash_table_destroy (domain->type_init_exception_hash);
1828                 domain->type_init_exception_hash = NULL;
1829         }
1830         g_hash_table_destroy (domain->class_init_trampoline_hash);
1831         domain->class_init_trampoline_hash = NULL;
1832         g_hash_table_destroy (domain->jump_trampoline_hash);
1833         domain->jump_trampoline_hash = NULL;
1834         g_hash_table_destroy (domain->finalizable_objects_hash);
1835         domain->finalizable_objects_hash = NULL;
1836         g_hash_table_destroy (domain->jit_trampoline_hash);
1837         domain->jit_trampoline_hash = NULL;
1838         g_hash_table_destroy (domain->delegate_trampoline_hash);
1839         domain->delegate_trampoline_hash = NULL;
1840         if (domain->shared_generics_hash) {
1841                 g_hash_table_destroy (domain->shared_generics_hash);
1842                 domain->shared_generics_hash = NULL;
1843         }
1844
1845         DeleteCriticalSection (&domain->assemblies_lock);
1846         DeleteCriticalSection (&domain->lock);
1847         domain->setup = NULL;
1848
1849         /* FIXME: anything else required ? */
1850
1851         mono_profiler_appdomain_event (domain, MONO_PROFILE_END_UNLOAD);
1852
1853         mono_gc_free_fixed (domain);
1854
1855         if ((domain == mono_root_domain))
1856                 mono_root_domain = NULL;
1857 }
1858
1859 /**
1860  * mono_domain_get_id:
1861  * @domainid: the ID
1862  *
1863  * Returns: the a domain for a specific domain id.
1864  */
1865 MonoDomain * 
1866 mono_domain_get_by_id (gint32 domainid) 
1867 {
1868         MonoDomain * domain;
1869
1870         mono_appdomains_lock ();
1871         if (domainid < appdomain_list_size)
1872                 domain = appdomains_list [domainid];
1873         else
1874                 domain = NULL;
1875         mono_appdomains_unlock ();
1876
1877         return domain;
1878 }
1879
1880 gint32
1881 mono_domain_get_id (MonoDomain *domain)
1882 {
1883         return domain->domain_id;
1884 }
1885
1886 void 
1887 mono_context_set (MonoAppContext * new_context)
1888 {
1889         SET_APPCONTEXT (new_context);
1890 }
1891
1892 MonoAppContext * 
1893 mono_context_get (void)
1894 {
1895         return GET_APPCONTEXT ();
1896 }
1897
1898 /* LOCKING: the caller holds the lock for this domain */
1899 void
1900 mono_domain_add_class_static_data (MonoDomain *domain, MonoClass *klass, gpointer data, guint32 *bitmap)
1901 {
1902         /* The first entry in the array is the index of the next free slot
1903          * and the total size of the array
1904          */
1905         int next;
1906         if (domain->static_data_array) {
1907                 int size = GPOINTER_TO_INT (domain->static_data_array [1]);
1908                 next = GPOINTER_TO_INT (domain->static_data_array [0]);
1909                 if (next >= size) {
1910                         gpointer *new_array = mono_gc_alloc_fixed (sizeof (gpointer) * (size * 2), NULL);
1911                         memcpy (new_array, domain->static_data_array, sizeof (gpointer) * size);
1912                         size *= 2;
1913                         new_array [1] = GINT_TO_POINTER (size);
1914                         mono_gc_free_fixed (domain->static_data_array);
1915                         domain->static_data_array = new_array;
1916                 }
1917         } else {
1918                 int size = 32;
1919                 gpointer *new_array = mono_gc_alloc_fixed (sizeof (gpointer) * size, NULL);
1920                 next = 2;
1921                 new_array [0] = GINT_TO_POINTER (next);
1922                 new_array [1] = GINT_TO_POINTER (size);
1923                 domain->static_data_array = new_array;
1924         }
1925         domain->static_data_array [next++] = data;
1926         domain->static_data_array [0] = GINT_TO_POINTER (next);
1927 }
1928
1929 MonoImage*
1930 mono_get_corlib (void)
1931 {
1932         return mono_defaults.corlib;
1933 }
1934
1935 MonoClass*
1936 mono_get_object_class (void)
1937 {
1938         return mono_defaults.object_class;
1939 }
1940
1941 MonoClass*
1942 mono_get_byte_class (void)
1943 {
1944         return mono_defaults.byte_class;
1945 }
1946
1947 MonoClass*
1948 mono_get_void_class (void)
1949 {
1950         return mono_defaults.void_class;
1951 }
1952
1953 MonoClass*
1954 mono_get_boolean_class (void)
1955 {
1956         return mono_defaults.boolean_class;
1957 }
1958
1959 MonoClass*
1960 mono_get_sbyte_class (void)
1961 {
1962         return mono_defaults.sbyte_class;
1963 }
1964
1965 MonoClass*
1966 mono_get_int16_class (void)
1967 {
1968         return mono_defaults.int16_class;
1969 }
1970
1971 MonoClass*
1972 mono_get_uint16_class (void)
1973 {
1974         return mono_defaults.uint16_class;
1975 }
1976
1977 MonoClass*
1978 mono_get_int32_class (void)
1979 {
1980         return mono_defaults.int32_class;
1981 }
1982
1983 MonoClass*
1984 mono_get_uint32_class (void)
1985 {
1986         return mono_defaults.uint32_class;
1987 }
1988
1989 MonoClass*
1990 mono_get_intptr_class (void)
1991 {
1992         return mono_defaults.int_class;
1993 }
1994
1995 MonoClass*
1996 mono_get_uintptr_class (void)
1997 {
1998         return mono_defaults.uint_class;
1999 }
2000
2001 MonoClass*
2002 mono_get_int64_class (void)
2003 {
2004         return mono_defaults.int64_class;
2005 }
2006
2007 MonoClass*
2008 mono_get_uint64_class (void)
2009 {
2010         return mono_defaults.uint64_class;
2011 }
2012
2013 MonoClass*
2014 mono_get_single_class (void)
2015 {
2016         return mono_defaults.single_class;
2017 }
2018
2019 MonoClass*
2020 mono_get_double_class (void)
2021 {
2022         return mono_defaults.double_class;
2023 }
2024
2025 MonoClass*
2026 mono_get_char_class (void)
2027 {
2028         return mono_defaults.char_class;
2029 }
2030
2031 MonoClass*
2032 mono_get_string_class (void)
2033 {
2034         return mono_defaults.string_class;
2035 }
2036
2037 MonoClass*
2038 mono_get_enum_class (void)
2039 {
2040         return mono_defaults.enum_class;
2041 }
2042
2043 MonoClass*
2044 mono_get_array_class (void)
2045 {
2046         return mono_defaults.array_class;
2047 }
2048
2049 MonoClass*
2050 mono_get_thread_class (void)
2051 {
2052         return mono_defaults.thread_class;
2053 }
2054
2055 MonoClass*
2056 mono_get_exception_class (void)
2057 {
2058         return mono_defaults.exception_class;
2059 }
2060
2061
2062 static char* get_attribute_value (const gchar **attribute_names, 
2063                                         const gchar **attribute_values, 
2064                                         const char *att_name)
2065 {
2066         int n;
2067         for (n=0; attribute_names[n] != NULL; n++) {
2068                 if (strcmp (attribute_names[n], att_name) == 0)
2069                         return g_strdup (attribute_values[n]);
2070         }
2071         return NULL;
2072 }
2073
2074 static void start_element (GMarkupParseContext *context, 
2075                            const gchar         *element_name,
2076                            const gchar        **attribute_names,
2077                            const gchar        **attribute_values,
2078                            gpointer             user_data,
2079                            GError             **error)
2080 {
2081         AppConfigInfo* app_config = (AppConfigInfo*) user_data;
2082         
2083         if (strcmp (element_name, "configuration") == 0) {
2084                 app_config->configuration_count++;
2085                 return;
2086         }
2087         if (strcmp (element_name, "startup") == 0) {
2088                 app_config->startup_count++;
2089                 return;
2090         }
2091         
2092         if (app_config->configuration_count != 1 || app_config->startup_count != 1)
2093                 return;
2094         
2095         if (strcmp (element_name, "requiredRuntime") == 0) {
2096                 app_config->required_runtime = get_attribute_value (attribute_names, attribute_values, "version");
2097         } else if (strcmp (element_name, "supportedRuntime") == 0) {
2098                 char *version = get_attribute_value (attribute_names, attribute_values, "version");
2099                 app_config->supported_runtimes = g_slist_append (app_config->supported_runtimes, version);
2100         }
2101 }
2102
2103 static void end_element   (GMarkupParseContext *context,
2104                            const gchar         *element_name,
2105                            gpointer             user_data,
2106                            GError             **error)
2107 {
2108         AppConfigInfo* app_config = (AppConfigInfo*) user_data;
2109         
2110         if (strcmp (element_name, "configuration") == 0) {
2111                 app_config->configuration_count--;
2112         } else if (strcmp (element_name, "startup") == 0) {
2113                 app_config->startup_count--;
2114         }
2115 }
2116
2117 static const GMarkupParser 
2118 mono_parser = {
2119         start_element,
2120         end_element,
2121         NULL,
2122         NULL,
2123         NULL
2124 };
2125
2126 static AppConfigInfo *
2127 app_config_parse (const char *exe_filename)
2128 {
2129         AppConfigInfo *app_config;
2130         GMarkupParseContext *context;
2131         char *text;
2132         gsize len;
2133         struct stat buf;
2134         const char *bundled_config;
2135         char *config_filename;
2136
2137         bundled_config = mono_config_string_for_assembly_file (exe_filename);
2138
2139         if (bundled_config) {
2140                 text = g_strdup (bundled_config);
2141                 len = strlen (text);
2142         } else {
2143                 config_filename = g_strconcat (exe_filename, ".config", NULL);
2144
2145                 if (stat (config_filename, &buf) != 0) {
2146                         g_free (config_filename);
2147                         return NULL;
2148                 }
2149         
2150                 if (!g_file_get_contents (config_filename, &text, &len, NULL)) {
2151                         g_free (config_filename);
2152                         return NULL;
2153                 }
2154                 g_free (config_filename);
2155         }
2156
2157         app_config = g_new0 (AppConfigInfo, 1);
2158
2159         context = g_markup_parse_context_new (&mono_parser, 0, app_config, NULL);
2160         if (g_markup_parse_context_parse (context, text, len, NULL)) {
2161                 g_markup_parse_context_end_parse (context, NULL);
2162         }
2163         g_markup_parse_context_free (context);
2164         g_free (text);
2165         return app_config;
2166 }
2167
2168 static void 
2169 app_config_free (AppConfigInfo* app_config)
2170 {
2171         char *rt;
2172         GSList *list = app_config->supported_runtimes;
2173         while (list != NULL) {
2174                 rt = (char*)list->data;
2175                 g_free (rt);
2176                 list = g_slist_next (list);
2177         }
2178         g_slist_free (app_config->supported_runtimes);
2179         g_free (app_config->required_runtime);
2180         g_free (app_config);
2181 }
2182
2183
2184 static const MonoRuntimeInfo*
2185 get_runtime_by_version (const char *version)
2186 {
2187         int n;
2188         int max = G_N_ELEMENTS (supported_runtimes);
2189         
2190         for (n=0; n<max; n++) {
2191                 if (strcmp (version, supported_runtimes[n].runtime_version) == 0)
2192                         return &supported_runtimes[n];
2193         }
2194         return NULL;
2195 }
2196
2197 static void
2198 get_runtimes_from_exe (const char *exe_file, MonoImage **exe_image, const MonoRuntimeInfo** runtimes)
2199 {
2200         AppConfigInfo* app_config;
2201         char *version;
2202         const MonoRuntimeInfo* runtime = NULL;
2203         MonoImage *image = NULL;
2204         
2205         app_config = app_config_parse (exe_file);
2206         
2207         if (app_config != NULL) {
2208                 /* Check supportedRuntime elements, if none is supported, fail.
2209                  * If there are no such elements, look for a requiredRuntime element.
2210                  */
2211                 if (app_config->supported_runtimes != NULL) {
2212                         int n = 0;
2213                         GSList *list = app_config->supported_runtimes;
2214                         while (list != NULL) {
2215                                 version = (char*) list->data;
2216                                 runtime = get_runtime_by_version (version);
2217                                 if (runtime != NULL)
2218                                         runtimes [n++] = runtime;
2219                                 list = g_slist_next (list);
2220                         }
2221                         runtimes [n] = NULL;
2222                         app_config_free (app_config);
2223                         return;
2224                 }
2225                 
2226                 /* Check the requiredRuntime element. This is for 1.0 apps only. */
2227                 if (app_config->required_runtime != NULL) {
2228                         runtimes [0] = get_runtime_by_version (app_config->required_runtime);
2229                         runtimes [1] = NULL;
2230                         app_config_free (app_config);
2231                         return;
2232                 }
2233                 app_config_free (app_config);
2234         }
2235         
2236         /* Look for a runtime with the exact version */
2237         image = mono_assembly_open_from_bundle (exe_file, NULL, FALSE);
2238
2239         if (image == NULL)
2240                 image = mono_image_open (exe_file, NULL);
2241
2242         if (image == NULL) {
2243                 /* The image is wrong or the file was not found. In this case return
2244                  * a default runtime and leave to the initialization method the work of
2245                  * reporting the error.
2246                  */
2247                 runtimes [0] = get_runtime_by_version (DEFAULT_RUNTIME_VERSION);
2248                 runtimes [1] = NULL;
2249                 return;
2250         }
2251
2252         *exe_image = image;
2253
2254         runtimes [0] = get_runtime_by_version (image->version);
2255         runtimes [1] = NULL;
2256 }
2257
2258
2259 /**
2260  * mono_get_runtime_info:
2261  *
2262  * Returns: the version of the current runtime instance.
2263  */
2264 const MonoRuntimeInfo*
2265 mono_get_runtime_info (void)
2266 {
2267         return current_runtime;
2268 }
2269
2270 gchar *
2271 mono_debugger_check_runtime_version (const char *filename)
2272 {
2273         const MonoRuntimeInfo* runtimes [G_N_ELEMENTS (supported_runtimes) + 1];
2274         const MonoRuntimeInfo *rinfo;
2275         MonoImage *image;
2276
2277         get_runtimes_from_exe (filename, &image, runtimes);
2278         rinfo = runtimes [0];
2279
2280         if (!rinfo)
2281                 return g_strdup_printf ("Cannot get runtime version from assembly `%s'", filename);
2282
2283         if (rinfo != current_runtime)
2284                 return g_strdup_printf ("The Mono Debugger is currently using the `%s' runtime, but "
2285                                         "the assembly `%s' requires version `%s'", current_runtime->runtime_version,
2286                                         filename, rinfo->runtime_version);
2287
2288         return NULL;
2289 }