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