Merge pull request #2780 from alexanderkyte/seq_point_optimize
[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  * Copyright 2011-2012 Xamarin, Inc (http://www.xamarin.com)
11  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
12  */
13
14 #include <config.h>
15 #include <glib.h>
16 #include <string.h>
17 #include <sys/stat.h>
18
19 #include <mono/metadata/gc-internals.h>
20
21 #include <mono/utils/atomic.h>
22 #include <mono/utils/mono-compiler.h>
23 #include <mono/utils/mono-logger-internals.h>
24 #include <mono/utils/mono-membar.h>
25 #include <mono/utils/mono-counters.h>
26 #include <mono/utils/hazard-pointer.h>
27 #include <mono/utils/mono-tls.h>
28 #include <mono/utils/mono-mmap.h>
29 #include <mono/utils/mono-threads.h>
30 #include <mono/metadata/object.h>
31 #include <mono/metadata/object-internals.h>
32 #include <mono/metadata/domain-internals.h>
33 #include <mono/metadata/class-internals.h>
34 #include <mono/metadata/assembly.h>
35 #include <mono/metadata/exception.h>
36 #include <mono/metadata/metadata-internals.h>
37 #include <mono/metadata/gc-internals.h>
38 #include <mono/metadata/appdomain.h>
39 #include <mono/metadata/mono-debug-debugger.h>
40 #include <mono/metadata/mono-config.h>
41 #include <mono/metadata/threads-types.h>
42 #include <mono/metadata/runtime.h>
43 #include <metadata/threads.h>
44 #include <metadata/profiler-private.h>
45 #include <mono/metadata/coree.h>
46 #include <mono/utils/w32handle.h>
47
48 //#define DEBUG_DOMAIN_UNLOAD 1
49
50 /* we need to use both the Tls* functions and __thread because
51  * some archs may generate faster jit code with one meachanism
52  * or the other (we used to do it because tls slots were GC-tracked,
53  * but we can't depend on this).
54  */
55 static MonoNativeTlsKey appdomain_thread_id;
56
57 #ifdef MONO_HAVE_FAST_TLS
58
59 MONO_FAST_TLS_DECLARE(tls_appdomain);
60
61 #define GET_APPDOMAIN() ((MonoDomain*)MONO_FAST_TLS_GET(tls_appdomain))
62
63 #define SET_APPDOMAIN(x) do { \
64         MonoThreadInfo *info; \
65         MONO_FAST_TLS_SET (tls_appdomain,x); \
66         mono_native_tls_set_value (appdomain_thread_id, x); \
67         mono_gc_set_current_thread_appdomain (x); \
68         info = mono_thread_info_current (); \
69         if (info) \
70                 mono_thread_info_tls_set (info, TLS_KEY_DOMAIN, (x));   \
71 } while (FALSE)
72
73 #else /* !MONO_HAVE_FAST_TLS */
74
75 #define GET_APPDOMAIN() ((MonoDomain *)mono_native_tls_get_value (appdomain_thread_id))
76 #define SET_APPDOMAIN(x) do {                                           \
77                 MonoThreadInfo *info;                                                           \
78                 mono_native_tls_set_value (appdomain_thread_id, x);     \
79                 mono_gc_set_current_thread_appdomain (x);               \
80                 info = mono_thread_info_current ();                             \
81                 if (info)                                                                                                \
82                         mono_thread_info_tls_set (info, TLS_KEY_DOMAIN, (x));   \
83         } while (FALSE)
84
85 #endif
86
87 #define GET_APPCONTEXT() (mono_thread_internal_current ()->current_appcontext)
88 #define SET_APPCONTEXT(x) MONO_OBJECT_SETREF (mono_thread_internal_current (), current_appcontext, (x))
89
90 static guint16 appdomain_list_size = 0;
91 static guint16 appdomain_next = 0;
92 static MonoDomain **appdomains_list = NULL;
93 static MonoImage *exe_image;
94 static gboolean debug_domain_unload;
95
96 gboolean mono_dont_free_domains;
97
98 #define mono_appdomains_lock() mono_coop_mutex_lock (&appdomains_mutex)
99 #define mono_appdomains_unlock() mono_coop_mutex_unlock (&appdomains_mutex)
100 static MonoCoopMutex appdomains_mutex;
101
102 static MonoDomain *mono_root_domain = NULL;
103
104 /* some statistics */
105 static int max_domain_code_size = 0;
106 static int max_domain_code_alloc = 0;
107 static int total_domain_code_alloc = 0;
108
109 /* AppConfigInfo: Information about runtime versions supported by an 
110  * aplication.
111  */
112 typedef struct {
113         GSList *supported_runtimes;
114         char *required_runtime;
115         int configuration_count;
116         int startup_count;
117 } AppConfigInfo;
118
119 static const MonoRuntimeInfo *current_runtime = NULL;
120
121 /* This is the list of runtime versions supported by this JIT.
122  */
123 static const MonoRuntimeInfo supported_runtimes[] = {
124         {"v4.0.30319","4.5", { {4,0,0,0}, {10,0,0,0}, {4,0,0,0}, {4,0,0,0} } },
125         {"mobile",    "2.1", { {2,0,5,0}, {10,0,0,0}, {2,0,5,0}, {2,0,5,0} } },
126         {"moonlight", "2.1", { {2,0,5,0}, { 9,0,0,0}, {3,5,0,0}, {3,0,0,0} } },
127 };
128
129
130 /* The stable runtime version */
131 #define DEFAULT_RUNTIME_VERSION "v4.0.30319"
132
133 /* Callbacks installed by the JIT */
134 static MonoCreateDomainFunc create_domain_hook;
135 static MonoFreeDomainFunc free_domain_hook;
136
137 /* AOT cache configuration */
138 static MonoAotCacheConfig aot_cache_config;
139
140 static void
141 get_runtimes_from_exe (const char *exe_file, MonoImage **exe_image, const MonoRuntimeInfo** runtimes);
142
143 static const MonoRuntimeInfo*
144 get_runtime_by_version (const char *version);
145
146 MonoNativeTlsKey
147 mono_domain_get_tls_key (void)
148 {
149         return appdomain_thread_id;
150 }
151
152 gint32
153 mono_domain_get_tls_offset (void)
154 {
155         int offset = -1;
156
157 #ifdef HOST_WIN32
158         if (appdomain_thread_id)
159                 offset = appdomain_thread_id;
160 #else
161         MONO_THREAD_VAR_OFFSET (tls_appdomain, offset);
162 #endif
163         return offset;
164 }
165
166 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
167 #define ALIGN_PTR_TO(ptr,align) (gpointer)((((gssize)(ptr)) + (align - 1)) & (~(align - 1)))
168
169 static LockFreeMempool*
170 lock_free_mempool_new (void)
171 {
172         return g_new0 (LockFreeMempool, 1);
173 }
174
175 static void
176 lock_free_mempool_free (LockFreeMempool *mp)
177 {
178         LockFreeMempoolChunk *chunk, *next;
179
180         chunk = mp->chunks;
181         while (chunk) {
182                 next = (LockFreeMempoolChunk *)chunk->prev;
183                 mono_vfree (chunk, mono_pagesize ());
184                 chunk = next;
185         }
186         g_free (mp);
187 }
188
189 /*
190  * This is async safe
191  */
192 static LockFreeMempoolChunk*
193 lock_free_mempool_chunk_new (LockFreeMempool *mp, int len)
194 {
195         LockFreeMempoolChunk *chunk, *prev;
196         int size;
197
198         size = mono_pagesize ();
199         while (size - sizeof (LockFreeMempoolChunk) < len)
200                 size += mono_pagesize ();
201         chunk = (LockFreeMempoolChunk *)mono_valloc (0, size, MONO_MMAP_READ|MONO_MMAP_WRITE);
202         g_assert (chunk);
203         chunk->mem = (guint8 *)ALIGN_PTR_TO ((char*)chunk + sizeof (LockFreeMempoolChunk), 16);
204         chunk->size = ((char*)chunk + size) - (char*)chunk->mem;
205         chunk->pos = 0;
206
207         /* Add to list of chunks lock-free */
208         while (TRUE) {
209                 prev = mp->chunks;
210                 if (InterlockedCompareExchangePointer ((volatile gpointer*)&mp->chunks, chunk, prev) == prev)
211                         break;
212         }
213         chunk->prev = prev;
214
215         return chunk;
216 }
217
218 /*
219  * This is async safe
220  */
221 static gpointer
222 lock_free_mempool_alloc0 (LockFreeMempool *mp, guint size)
223 {
224         LockFreeMempoolChunk *chunk;
225         gpointer res;
226         int oldpos;
227
228         // FIXME: Free the allocator
229
230         size = ALIGN_TO (size, 8);
231         chunk = mp->current;
232         if (!chunk) {
233                 chunk = lock_free_mempool_chunk_new (mp, size);
234                 mono_memory_barrier ();
235                 /* Publish */
236                 mp->current = chunk;
237         }
238
239         /* The code below is lock-free, 'chunk' is shared state */
240         oldpos = InterlockedExchangeAdd (&chunk->pos, size);
241         if (oldpos + size > chunk->size) {
242                 chunk = lock_free_mempool_chunk_new (mp, size);
243                 g_assert (chunk->pos + size <= chunk->size);
244                 res = chunk->mem;
245                 chunk->pos += size;
246                 mono_memory_barrier ();
247                 mp->current = chunk;
248         } else {
249                 res = (char*)chunk->mem + oldpos;
250         }
251
252         return res;
253 }
254
255 void
256 mono_install_create_domain_hook (MonoCreateDomainFunc func)
257 {
258         create_domain_hook = func;
259 }
260
261 void
262 mono_install_free_domain_hook (MonoFreeDomainFunc func)
263 {
264         free_domain_hook = func;
265 }
266
267 /**
268  * mono_string_equal:
269  * @s1: First string to compare
270  * @s2: Second string to compare
271  *
272  * Compares two `MonoString*` instances ordinally for equality.
273  *
274  * Returns FALSE if the strings differ.
275  */
276 gboolean
277 mono_string_equal (MonoString *s1, MonoString *s2)
278 {
279         int l1 = mono_string_length (s1);
280         int l2 = mono_string_length (s2);
281
282         if (s1 == s2)
283                 return TRUE;
284         if (l1 != l2)
285                 return FALSE;
286
287         return memcmp (mono_string_chars (s1), mono_string_chars (s2), l1 * 2) == 0; 
288 }
289
290 /**
291  * mono_string_hash:
292  * @s: the string to hash
293  *
294  * Compute the hash for a `MonoString*`
295  * Returns the hash for the string.
296  */
297 guint
298 mono_string_hash (MonoString *s)
299 {
300         const guint16 *p = mono_string_chars (s);
301         int i, len = mono_string_length (s);
302         guint h = 0;
303
304         for (i = 0; i < len; i++) {
305                 h = (h << 5) - h + *p;
306                 p++;
307         }
308
309         return h;       
310 }
311
312 static gboolean
313 mono_ptrarray_equal (gpointer *s1, gpointer *s2)
314 {
315         int len = GPOINTER_TO_INT (s1 [0]);
316         if (len != GPOINTER_TO_INT (s2 [0]))
317                 return FALSE;
318
319         return memcmp (s1 + 1, s2 + 1, len * sizeof(gpointer)) == 0; 
320 }
321
322 static guint
323 mono_ptrarray_hash (gpointer *s)
324 {
325         int i;
326         int len = GPOINTER_TO_INT (s [0]);
327         guint hash = 0;
328         
329         for (i = 1; i < len; i++)
330                 hash += GPOINTER_TO_UINT (s [i]);
331
332         return hash;    
333 }
334
335 /*
336  * Allocate an id for domain and set domain->domain_id.
337  * LOCKING: must be called while holding appdomains_mutex.
338  * We try to assign low numbers to the domain, so it can be used
339  * as an index in data tables to lookup domain-specific info
340  * with minimal memory overhead. We also try not to reuse the
341  * same id too quickly (to help debugging).
342  */
343 static int
344 domain_id_alloc (MonoDomain *domain)
345 {
346         int id = -1, i;
347         if (!appdomains_list) {
348                 appdomain_list_size = 2;
349                 appdomains_list = (MonoDomain **)mono_gc_alloc_fixed (appdomain_list_size * sizeof (void*), MONO_GC_DESCRIPTOR_NULL, MONO_ROOT_SOURCE_DOMAIN, "domains list");
350         }
351         for (i = appdomain_next; i < appdomain_list_size; ++i) {
352                 if (!appdomains_list [i]) {
353                         id = i;
354                         break;
355                 }
356         }
357         if (id == -1) {
358                 for (i = 0; i < appdomain_next; ++i) {
359                         if (!appdomains_list [i]) {
360                                 id = i;
361                                 break;
362                         }
363                 }
364         }
365         if (id == -1) {
366                 MonoDomain **new_list;
367                 int new_size = appdomain_list_size * 2;
368                 if (new_size >= (1 << 16))
369                         g_assert_not_reached ();
370                 id = appdomain_list_size;
371                 new_list = (MonoDomain **)mono_gc_alloc_fixed (new_size * sizeof (void*), MONO_GC_DESCRIPTOR_NULL, MONO_ROOT_SOURCE_DOMAIN, "domains list");
372                 memcpy (new_list, appdomains_list, appdomain_list_size * sizeof (void*));
373                 mono_gc_free_fixed (appdomains_list);
374                 appdomains_list = new_list;
375                 appdomain_list_size = new_size;
376         }
377         domain->domain_id = id;
378         appdomains_list [id] = domain;
379         appdomain_next++;
380         if (appdomain_next > appdomain_list_size)
381                 appdomain_next = 0;
382         return id;
383 }
384
385 static gsize domain_gc_bitmap [sizeof(MonoDomain)/4/32 + 1];
386 static MonoGCDescriptor domain_gc_desc = MONO_GC_DESCRIPTOR_NULL;
387 static guint32 domain_shadow_serial = 0L;
388
389 /**
390  * mono_domain_create:
391  *
392  * Creates a new application domain, the unmanaged representation
393  * of the actual domain.   Usually you will want to create the
394  *
395  * Application domains provide an isolation facilty for assemblies.   You
396  * can load assemblies and execute code in them that will not be visible
397  * to other application domains.   This is a runtime-based virtualization
398  * technology.
399  *
400  * It is possible to unload domains, which unloads the assemblies and
401  * data that was allocated in that domain.
402  *
403  * When a domain is created a mempool is allocated for domain-specific
404  * structures, along a dedicated code manager to hold code that is
405  * associated with the domain.
406  *
407  * Returns: New initialized MonoDomain, with no configuration or assemblies
408  * loaded into it.
409  */
410 MonoDomain *
411 mono_domain_create (void)
412 {
413         MonoDomain *domain;
414         guint32 shadow_serial;
415   
416         mono_appdomains_lock ();
417         shadow_serial = domain_shadow_serial++;
418   
419         if (!domain_gc_desc) {
420                 unsigned int i, bit = 0;
421                 for (i = G_STRUCT_OFFSET (MonoDomain, MONO_DOMAIN_FIRST_OBJECT); i < G_STRUCT_OFFSET (MonoDomain, MONO_DOMAIN_FIRST_GC_TRACKED); i += sizeof (gpointer)) {
422                         bit = i / sizeof (gpointer);
423                         domain_gc_bitmap [bit / 32] |= (gsize) 1 << (bit % 32);
424                 }
425                 domain_gc_desc = mono_gc_make_descr_from_bitmap ((gsize*)domain_gc_bitmap, bit + 1);
426         }
427         mono_appdomains_unlock ();
428
429 #ifdef HAVE_BOEHM_GC
430         /*
431          * Boehm doesn't like roots inside GC allocated objects, and alloc_fixed returns
432          * a GC_MALLOC-ed object, contrary to the api docs. This causes random crashes when
433          * running the corlib test suite.
434          * To solve this, we pass a NULL descriptor, and don't register roots.
435          */
436         domain = (MonoDomain *)mono_gc_alloc_fixed (sizeof (MonoDomain), NULL, MONO_ROOT_SOURCE_DOMAIN, "domain object");
437 #else
438         domain = (MonoDomain *)mono_gc_alloc_fixed (sizeof (MonoDomain), domain_gc_desc, MONO_ROOT_SOURCE_DOMAIN, "domain object");
439         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), MONO_GC_DESCRIPTOR_NULL, MONO_ROOT_SOURCE_DOMAIN, "misc domain fields");
440 #endif
441         domain->shadow_serial = shadow_serial;
442         domain->domain = NULL;
443         domain->setup = NULL;
444         domain->friendly_name = NULL;
445         domain->search_path = NULL;
446
447         mono_profiler_appdomain_event (domain, MONO_PROFILE_START_LOAD);
448
449         domain->mp = mono_mempool_new ();
450         domain->code_mp = mono_code_manager_new ();
451         domain->lock_free_mp = lock_free_mempool_new ();
452         domain->env = mono_g_hash_table_new_type ((GHashFunc)mono_string_hash, (GCompareFunc)mono_string_equal, MONO_HASH_KEY_VALUE_GC, MONO_ROOT_SOURCE_DOMAIN, "domain environment variables table");
453         domain->domain_assemblies = NULL;
454         domain->assembly_bindings = NULL;
455         domain->assembly_bindings_parsed = FALSE;
456         domain->class_vtable_array = g_ptr_array_new ();
457         domain->proxy_vtable_hash = g_hash_table_new ((GHashFunc)mono_ptrarray_hash, (GCompareFunc)mono_ptrarray_equal);
458         domain->static_data_array = NULL;
459         mono_jit_code_hash_init (&domain->jit_code_hash);
460         domain->ldstr_table = mono_g_hash_table_new_type ((GHashFunc)mono_string_hash, (GCompareFunc)mono_string_equal, MONO_HASH_KEY_VALUE_GC, MONO_ROOT_SOURCE_DOMAIN, "domain string constants table");
461         domain->num_jit_info_tables = 1;
462         domain->jit_info_table = mono_jit_info_table_new (domain);
463         domain->jit_info_free_queue = NULL;
464         domain->finalizable_objects_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
465         domain->ftnptrs_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
466
467         mono_coop_mutex_init_recursive (&domain->lock);
468
469         mono_os_mutex_init_recursive (&domain->assemblies_lock);
470         mono_os_mutex_init_recursive (&domain->jit_code_hash_lock);
471         mono_os_mutex_init_recursive (&domain->finalizable_objects_hash_lock);
472
473         domain->method_rgctx_hash = NULL;
474
475         mono_appdomains_lock ();
476         domain_id_alloc (domain);
477         mono_appdomains_unlock ();
478
479 #ifndef DISABLE_PERFCOUNTERS
480         mono_perfcounters->loader_appdomains++;
481         mono_perfcounters->loader_total_appdomains++;
482 #endif
483
484         mono_debug_domain_create (domain);
485
486         if (create_domain_hook)
487                 create_domain_hook (domain);
488
489         mono_profiler_appdomain_loaded (domain, MONO_PROFILE_OK);
490         
491         return domain;
492 }
493
494 /**
495  * mono_init_internal:
496  * 
497  * Creates the initial application domain and initializes the mono_defaults
498  * structure.
499  * This function is guaranteed to not run any IL code.
500  * If exe_filename is not NULL, the method will determine the required runtime
501  * from the exe configuration file or the version PE field.
502  * If runtime_version is not NULL, that runtime version will be used.
503  * Either exe_filename or runtime_version must be provided.
504  *
505  * Returns: the initial domain.
506  */
507 static MonoDomain *
508 mono_init_internal (const char *filename, const char *exe_filename, const char *runtime_version)
509 {
510         static MonoDomain *domain = NULL;
511         MonoAssembly *ass = NULL;
512         MonoImageOpenStatus status = MONO_IMAGE_OK;
513         const MonoRuntimeInfo* runtimes [G_N_ELEMENTS (supported_runtimes) + 1];
514         int n, dummy;
515
516 #ifdef DEBUG_DOMAIN_UNLOAD
517         debug_domain_unload = TRUE;
518 #endif
519
520         if (domain)
521                 g_assert_not_reached ();
522
523 #ifdef HOST_WIN32
524         /* Avoid system error message boxes. */
525         SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
526 #endif
527
528 #ifndef HOST_WIN32
529         mono_w32handle_init ();
530         wapi_init ();
531 #endif
532
533 #ifndef DISABLE_PERFCOUNTERS
534         mono_perfcounters_init ();
535 #endif
536         mono_counters_init ();
537
538         mono_counters_register ("Max native code in a domain", MONO_COUNTER_INT|MONO_COUNTER_JIT, &max_domain_code_size);
539         mono_counters_register ("Max code space allocated in a domain", MONO_COUNTER_INT|MONO_COUNTER_JIT, &max_domain_code_alloc);
540         mono_counters_register ("Total code space allocated", MONO_COUNTER_INT|MONO_COUNTER_JIT, &total_domain_code_alloc);
541
542         mono_gc_base_init ();
543         mono_thread_info_attach (&dummy);
544
545         MONO_FAST_TLS_INIT (tls_appdomain);
546         mono_native_tls_alloc (&appdomain_thread_id, NULL);
547
548         mono_coop_mutex_init_recursive (&appdomains_mutex);
549
550         mono_metadata_init ();
551         mono_images_init ();
552         mono_assemblies_init ();
553         mono_classes_init ();
554         mono_loader_init ();
555         mono_reflection_init ();
556         mono_runtime_init_tls ();
557
558         /* FIXME: When should we release this memory? */
559         MONO_GC_REGISTER_ROOT_FIXED (appdomains_list, MONO_ROOT_SOURCE_DOMAIN, "domains list");
560
561         domain = mono_domain_create ();
562         mono_root_domain = domain;
563
564         SET_APPDOMAIN (domain);
565         
566         /* Get a list of runtimes supported by the exe */
567         if (exe_filename != NULL) {
568                 /*
569                  * This function will load the exe file as a MonoImage. We need to close it, but
570                  * that would mean it would be reloaded later. So instead, we save it to
571                  * exe_image, and close it during shutdown.
572                  */
573                 get_runtimes_from_exe (exe_filename, &exe_image, runtimes);
574 #ifdef HOST_WIN32
575                 if (!exe_image) {
576                         exe_image = mono_assembly_open_from_bundle (exe_filename, NULL, FALSE);
577                         if (!exe_image)
578                                 exe_image = mono_image_open (exe_filename, NULL);
579                 }
580                 mono_fixup_exe_image (exe_image);
581 #endif
582         } else if (runtime_version != NULL) {
583                 runtimes [0] = get_runtime_by_version (runtime_version);
584                 runtimes [1] = NULL;
585         }
586
587         if (runtimes [0] == NULL) {
588                 const MonoRuntimeInfo *default_runtime = get_runtime_by_version (DEFAULT_RUNTIME_VERSION);
589                 runtimes [0] = default_runtime;
590                 runtimes [1] = NULL;
591                 g_print ("WARNING: The runtime version supported by this application is unavailable.\n");
592                 g_print ("Using default runtime: %s\n", default_runtime->runtime_version); 
593         }
594
595         /* The selected runtime will be the first one for which there is a mscrolib.dll */
596         for (n = 0; runtimes [n] != NULL && ass == NULL; n++) {
597                 current_runtime = runtimes [n];
598                 ass = mono_assembly_load_corlib (current_runtime, &status);
599                 if (status != MONO_IMAGE_OK && status != MONO_IMAGE_ERROR_ERRNO)
600                         break;
601
602         }
603         
604         if ((status != MONO_IMAGE_OK) || (ass == NULL)) {
605                 switch (status){
606                 case MONO_IMAGE_ERROR_ERRNO: {
607                         char *corlib_file = g_build_filename (mono_assembly_getrootdir (), "mono", current_runtime->framework_version, "mscorlib.dll", NULL);
608                         g_print ("The assembly mscorlib.dll was not found or could not be loaded.\n");
609                         g_print ("It should have been installed in the `%s' directory.\n", corlib_file);
610                         g_free (corlib_file);
611                         break;
612                 }
613                 case MONO_IMAGE_IMAGE_INVALID:
614                         g_print ("The file %s/mscorlib.dll is an invalid CIL image\n",
615                                  mono_assembly_getrootdir ());
616                         break;
617                 case MONO_IMAGE_MISSING_ASSEMBLYREF:
618                         g_print ("Missing assembly reference in %s/mscorlib.dll\n",
619                                  mono_assembly_getrootdir ());
620                         break;
621                 case MONO_IMAGE_OK:
622                         /* to suppress compiler warning */
623                         break;
624                 }
625                 
626                 exit (1);
627         }
628         mono_defaults.corlib = mono_assembly_get_image (ass);
629
630         mono_defaults.object_class = mono_class_load_from_name (
631                 mono_defaults.corlib, "System", "Object");
632
633         mono_defaults.void_class = mono_class_load_from_name (
634                 mono_defaults.corlib, "System", "Void");
635
636         mono_defaults.boolean_class = mono_class_load_from_name (
637                 mono_defaults.corlib, "System", "Boolean");
638
639         mono_defaults.byte_class = mono_class_load_from_name (
640                 mono_defaults.corlib, "System", "Byte");
641
642         mono_defaults.sbyte_class = mono_class_load_from_name (
643                 mono_defaults.corlib, "System", "SByte");
644
645         mono_defaults.int16_class = mono_class_load_from_name (
646                 mono_defaults.corlib, "System", "Int16");
647
648         mono_defaults.uint16_class = mono_class_load_from_name (
649                 mono_defaults.corlib, "System", "UInt16");
650
651         mono_defaults.int32_class = mono_class_load_from_name (
652                 mono_defaults.corlib, "System", "Int32");
653
654         mono_defaults.uint32_class = mono_class_load_from_name (
655                 mono_defaults.corlib, "System", "UInt32");
656
657         mono_defaults.uint_class = mono_class_load_from_name (
658                 mono_defaults.corlib, "System", "UIntPtr");
659
660         mono_defaults.int_class = mono_class_load_from_name (
661                 mono_defaults.corlib, "System", "IntPtr");
662
663         mono_defaults.int64_class = mono_class_load_from_name (
664                 mono_defaults.corlib, "System", "Int64");
665
666         mono_defaults.uint64_class = mono_class_load_from_name (
667                 mono_defaults.corlib, "System", "UInt64");
668
669         mono_defaults.single_class = mono_class_load_from_name (
670                 mono_defaults.corlib, "System", "Single");
671
672         mono_defaults.double_class = mono_class_load_from_name (
673                 mono_defaults.corlib, "System", "Double");
674
675         mono_defaults.char_class = mono_class_load_from_name (
676                 mono_defaults.corlib, "System", "Char");
677
678         mono_defaults.string_class = mono_class_load_from_name (
679                 mono_defaults.corlib, "System", "String");
680
681         mono_defaults.enum_class = mono_class_load_from_name (
682                 mono_defaults.corlib, "System", "Enum");
683
684         mono_defaults.array_class = mono_class_load_from_name (
685                 mono_defaults.corlib, "System", "Array");
686
687         mono_defaults.delegate_class = mono_class_load_from_name (
688                 mono_defaults.corlib, "System", "Delegate");
689
690         mono_defaults.multicastdelegate_class = mono_class_load_from_name (
691                 mono_defaults.corlib, "System", "MulticastDelegate");
692
693         mono_defaults.asyncresult_class = mono_class_load_from_name (
694                 mono_defaults.corlib, "System.Runtime.Remoting.Messaging", 
695                 "AsyncResult");
696
697         mono_defaults.manualresetevent_class = mono_class_load_from_name (
698                 mono_defaults.corlib, "System.Threading", "ManualResetEvent");
699
700         mono_defaults.typehandle_class = mono_class_load_from_name (
701                 mono_defaults.corlib, "System", "RuntimeTypeHandle");
702
703         mono_defaults.methodhandle_class = mono_class_load_from_name (
704                 mono_defaults.corlib, "System", "RuntimeMethodHandle");
705
706         mono_defaults.fieldhandle_class = mono_class_load_from_name (
707                 mono_defaults.corlib, "System", "RuntimeFieldHandle");
708
709         mono_defaults.systemtype_class = mono_class_load_from_name (
710                 mono_defaults.corlib, "System", "Type");
711
712         mono_defaults.runtimetype_class = mono_class_load_from_name (
713                 mono_defaults.corlib, "System", "RuntimeType");
714
715         mono_defaults.exception_class = mono_class_load_from_name (
716                 mono_defaults.corlib, "System", "Exception");
717
718         mono_defaults.threadabortexception_class = mono_class_load_from_name (
719                 mono_defaults.corlib, "System.Threading", "ThreadAbortException");
720
721         mono_defaults.thread_class = mono_class_load_from_name (
722                 mono_defaults.corlib, "System.Threading", "Thread");
723
724         mono_defaults.internal_thread_class = mono_class_load_from_name (
725                 mono_defaults.corlib, "System.Threading", "InternalThread");
726
727         mono_defaults.appdomain_class = mono_class_load_from_name (
728                 mono_defaults.corlib, "System", "AppDomain");
729
730 #ifndef DISABLE_REMOTING
731         mono_defaults.transparent_proxy_class = mono_class_load_from_name (
732                 mono_defaults.corlib, "System.Runtime.Remoting.Proxies", "TransparentProxy");
733
734         mono_defaults.real_proxy_class = mono_class_load_from_name (
735                 mono_defaults.corlib, "System.Runtime.Remoting.Proxies", "RealProxy");
736
737         mono_defaults.marshalbyrefobject_class =  mono_class_load_from_name (
738                 mono_defaults.corlib, "System", "MarshalByRefObject");
739
740         mono_defaults.iremotingtypeinfo_class = mono_class_load_from_name (
741                 mono_defaults.corlib, "System.Runtime.Remoting", "IRemotingTypeInfo");
742
743 #endif
744
745         mono_defaults.mono_method_message_class = mono_class_load_from_name (
746                 mono_defaults.corlib, "System.Runtime.Remoting.Messaging", "MonoMethodMessage");
747
748         mono_defaults.field_info_class = mono_class_load_from_name (
749                 mono_defaults.corlib, "System.Reflection", "FieldInfo");
750
751         mono_defaults.method_info_class = mono_class_load_from_name (
752                 mono_defaults.corlib, "System.Reflection", "MethodInfo");
753
754         mono_defaults.stringbuilder_class = mono_class_load_from_name (
755                 mono_defaults.corlib, "System.Text", "StringBuilder");
756
757         mono_defaults.math_class = mono_class_load_from_name (
758                 mono_defaults.corlib, "System", "Math");
759
760         mono_defaults.stack_frame_class = mono_class_load_from_name (
761                 mono_defaults.corlib, "System.Diagnostics", "StackFrame");
762
763         mono_defaults.stack_trace_class = mono_class_load_from_name (
764                 mono_defaults.corlib, "System.Diagnostics", "StackTrace");
765
766         mono_defaults.marshal_class = mono_class_load_from_name (
767                 mono_defaults.corlib, "System.Runtime.InteropServices", "Marshal");
768
769         mono_defaults.typed_reference_class = mono_class_load_from_name (
770                 mono_defaults.corlib, "System", "TypedReference");
771
772         mono_defaults.argumenthandle_class = mono_class_load_from_name (
773                 mono_defaults.corlib, "System", "RuntimeArgumentHandle");
774
775         mono_defaults.monitor_class = mono_class_load_from_name (
776                 mono_defaults.corlib, "System.Threading", "Monitor");
777         /*
778         Not using GENERATE_TRY_GET_CLASS_WITH_CACHE_DECL as this type is heavily checked by sgen when computing finalization.
779         */
780         mono_defaults.critical_finalizer_object = mono_class_try_load_from_name (mono_defaults.corlib,
781                         "System.Runtime.ConstrainedExecution", "CriticalFinalizerObject");
782
783         mono_assembly_load_friends (ass);
784
785         mono_defaults.handleref_class = mono_class_try_load_from_name (
786                 mono_defaults.corlib, "System.Runtime.InteropServices", "HandleRef");
787
788         mono_defaults.attribute_class = mono_class_load_from_name (
789                 mono_defaults.corlib, "System", "Attribute");
790
791         mono_defaults.customattribute_data_class = mono_class_load_from_name (
792                 mono_defaults.corlib, "System.Reflection", "CustomAttributeData");
793
794         mono_class_init (mono_defaults.array_class);
795         mono_defaults.generic_nullable_class = mono_class_load_from_name (
796                 mono_defaults.corlib, "System", "Nullable`1");
797         mono_defaults.generic_ilist_class = mono_class_load_from_name (
798                 mono_defaults.corlib, "System.Collections.Generic", "IList`1");
799         mono_defaults.generic_ireadonlylist_class = mono_class_load_from_name (
800                 mono_defaults.corlib, "System.Collections.Generic", "IReadOnlyList`1");
801
802         mono_defaults.threadpool_wait_callback_class = mono_class_load_from_name (
803                 mono_defaults.corlib, "System.Threading", "_ThreadPoolWaitCallback");
804
805         mono_defaults.threadpool_perform_wait_callback_method = mono_class_get_method_from_name (
806                 mono_defaults.threadpool_wait_callback_class, "PerformWaitCallback", 0);
807
808         domain->friendly_name = g_path_get_basename (filename);
809
810         mono_profiler_appdomain_name (domain, domain->friendly_name);
811
812         return domain;
813 }
814
815 /**
816  * mono_init:
817  * 
818  * Creates the initial application domain and initializes the mono_defaults
819  * structure.
820  *
821  * This function is guaranteed to not run any IL code.
822  * The runtime is initialized using the default runtime version.
823  *
824  * Returns: the initial domain.
825  */
826 MonoDomain *
827 mono_init (const char *domain_name)
828 {
829         return mono_init_internal (domain_name, NULL, DEFAULT_RUNTIME_VERSION);
830 }
831
832 /**
833  * mono_init_from_assembly:
834  * @domain_name: name to give to the initial domain
835  * @filename: filename to load on startup
836  *
837  * Used by the runtime, users should use mono_jit_init instead.
838  *
839  * Creates the initial application domain and initializes the mono_defaults
840  * structure.
841  * This function is guaranteed to not run any IL code.
842  * The runtime is initialized using the runtime version required by the
843  * provided executable. The version is determined by looking at the exe 
844  * configuration file and the version PE field)
845  *
846  * Returns: the initial domain.
847  */
848 MonoDomain *
849 mono_init_from_assembly (const char *domain_name, const char *filename)
850 {
851         return mono_init_internal (domain_name, filename, NULL);
852 }
853
854 /**
855  * mono_init_version:
856  * 
857  * Used by the runtime, users should use mono_jit_init instead.
858  * 
859  * Creates the initial application domain and initializes the mono_defaults
860  * structure.
861  *
862  * This function is guaranteed to not run any IL code.
863  * The runtime is initialized using the provided rutime version.
864  *
865  * Returns: the initial domain.
866  */
867 MonoDomain *
868 mono_init_version (const char *domain_name, const char *version)
869 {
870         return mono_init_internal (domain_name, NULL, version);
871 }
872
873 /**
874  * mono_cleanup:
875  *
876  * Cleans up all metadata modules. 
877  */
878 void
879 mono_cleanup (void)
880 {
881         mono_close_exe_image ();
882
883         mono_defaults.corlib = NULL;
884
885         mono_config_cleanup ();
886         mono_loader_cleanup ();
887         mono_classes_cleanup ();
888         mono_assemblies_cleanup ();
889         mono_debug_cleanup ();
890         mono_images_cleanup ();
891         mono_metadata_cleanup ();
892
893         mono_native_tls_free (appdomain_thread_id);
894         mono_coop_mutex_destroy (&appdomains_mutex);
895
896 #ifndef HOST_WIN32
897         wapi_cleanup ();
898         mono_w32handle_cleanup ();
899 #endif
900 }
901
902 void
903 mono_close_exe_image (void)
904 {
905         if (exe_image)
906                 mono_image_close (exe_image);
907 }
908
909 /**
910  * mono_get_root_domain:
911  *
912  * The root AppDomain is the initial domain created by the runtime when it is
913  * initialized.  Programs execute on this AppDomain, but can create new ones
914  * later.   Currently there is no unmanaged API to create new AppDomains, this
915  * must be done from managed code.
916  *
917  * Returns: the root appdomain, to obtain the current domain, use mono_domain_get ()
918  */
919 MonoDomain*
920 mono_get_root_domain (void)
921 {
922         return mono_root_domain;
923 }
924
925 /**
926  * mono_domain_get:
927  *
928  * This method returns the value of the current MonoDomain that this thread
929  * and code are running under.   To obtain the root domain use
930  * mono_get_root_domain() API.
931  *
932  * Returns: the current domain
933  */
934 MonoDomain *
935 mono_domain_get ()
936 {
937         return GET_APPDOMAIN ();
938 }
939
940 void
941 mono_domain_unset (void)
942 {
943         SET_APPDOMAIN (NULL);
944 }
945
946 void
947 mono_domain_set_internal_with_options (MonoDomain *domain, gboolean migrate_exception)
948 {
949         MonoInternalThread *thread;
950
951         if (mono_domain_get () == domain)
952                 return;
953
954         SET_APPDOMAIN (domain);
955         SET_APPCONTEXT (domain->default_context);
956
957         if (migrate_exception) {
958                 thread = mono_thread_internal_current ();
959                 if (!thread->abort_exc)
960                         return;
961
962                 g_assert (thread->abort_exc->object.vtable->domain != domain);
963                 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
964                 g_assert (thread->abort_exc->object.vtable->domain == domain);
965         }
966 }
967
968 /**
969  * mono_domain_set_internal:
970  * @domain: the new domain
971  *
972  * Sets the current domain to @domain.
973  */
974 void
975 mono_domain_set_internal (MonoDomain *domain)
976 {
977         mono_domain_set_internal_with_options (domain, TRUE);
978 }
979
980 /**
981  * mono_domain_foreach:
982  * @func: function to invoke with the domain data
983  * @user_data: user-defined pointer that is passed to the supplied @func fo reach domain
984  *
985  * Use this method to safely iterate over all the loaded application
986  * domains in the current runtime.   The provided @func is invoked with a
987  * pointer to the MonoDomain and is given the value of the @user_data
988  * parameter which can be used to pass state to your called routine.
989  */
990 void
991 mono_domain_foreach (MonoDomainFunc func, gpointer user_data)
992 {
993         int i, size;
994         MonoDomain **copy;
995
996         /*
997          * Create a copy of the data to avoid calling the user callback
998          * inside the lock because that could lead to deadlocks.
999          * We can do this because this function is not perf. critical.
1000          */
1001         mono_appdomains_lock ();
1002         size = appdomain_list_size;
1003         copy = (MonoDomain **)mono_gc_alloc_fixed (appdomain_list_size * sizeof (void*), MONO_GC_DESCRIPTOR_NULL, MONO_ROOT_SOURCE_DOMAIN, "temporary domains list");
1004         memcpy (copy, appdomains_list, appdomain_list_size * sizeof (void*));
1005         mono_appdomains_unlock ();
1006
1007         for (i = 0; i < size; ++i) {
1008                 if (copy [i])
1009                         func (copy [i], user_data);
1010         }
1011
1012         mono_gc_free_fixed (copy);
1013 }
1014
1015 /**
1016  * mono_domain_assembly_open:
1017  * @domain: the application domain
1018  * @name: file name of the assembly
1019  *
1020  * fixme: maybe we should integrate this with mono_assembly_open ??
1021  */
1022 MonoAssembly *
1023 mono_domain_assembly_open (MonoDomain *domain, const char *name)
1024 {
1025         MonoDomain *current;
1026         MonoAssembly *ass;
1027         GSList *tmp;
1028
1029         mono_domain_assemblies_lock (domain);
1030         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1031                 ass = (MonoAssembly *)tmp->data;
1032                 if (strcmp (name, ass->aname.name) == 0) {
1033                         mono_domain_assemblies_unlock (domain);
1034                         return ass;
1035                 }
1036         }
1037         mono_domain_assemblies_unlock (domain);
1038
1039         if (domain != mono_domain_get ()) {
1040                 current = mono_domain_get ();
1041
1042                 mono_domain_set (domain, FALSE);
1043                 ass = mono_assembly_open (name, NULL);
1044                 mono_domain_set (current, FALSE);
1045         } else {
1046                 ass = mono_assembly_open (name, NULL);
1047         }
1048
1049         return ass;
1050 }
1051
1052 static void
1053 unregister_vtable_reflection_type (MonoVTable *vtable)
1054 {
1055         MonoObject *type = (MonoObject *)vtable->type;
1056
1057         if (type->vtable->klass != mono_defaults.runtimetype_class)
1058                 MONO_GC_UNREGISTER_ROOT_IF_MOVING (vtable->type);
1059 }
1060
1061 /**
1062  * mono_domain_free:
1063  * @domain: the domain to release
1064  * @force: if true, it allows the root domain to be released (used at shutdown only).
1065  *
1066  * This releases the resources associated with the specific domain.
1067  * This is a low-level function that is invoked by the AppDomain infrastructure
1068  * when necessary.
1069  */
1070 void
1071 mono_domain_free (MonoDomain *domain, gboolean force)
1072 {
1073         int code_size, code_alloc;
1074         GSList *tmp;
1075         gpointer *p;
1076
1077         if ((domain == mono_root_domain) && !force) {
1078                 g_warning ("cant unload root domain");
1079                 return;
1080         }
1081
1082         if (mono_dont_free_domains)
1083                 return;
1084
1085         mono_profiler_appdomain_event (domain, MONO_PROFILE_START_UNLOAD);
1086
1087         mono_debug_domain_unload (domain);
1088
1089         mono_appdomains_lock ();
1090         appdomains_list [domain->domain_id] = NULL;
1091         mono_appdomains_unlock ();
1092
1093         /* must do this early as it accesses fields and types */
1094         if (domain->special_static_fields) {
1095                 mono_alloc_special_static_data_free (domain->special_static_fields);
1096                 g_hash_table_destroy (domain->special_static_fields);
1097                 domain->special_static_fields = NULL;
1098         }
1099
1100         /*
1101          * We must destroy all these hash tables here because they
1102          * contain references to managed objects belonging to the
1103          * domain.  Once we let the GC clear the domain there must be
1104          * no more such references, or we'll crash if a collection
1105          * occurs.
1106          */
1107         mono_g_hash_table_destroy (domain->ldstr_table);
1108         domain->ldstr_table = NULL;
1109
1110         mono_g_hash_table_destroy (domain->env);
1111         domain->env = NULL;
1112
1113         mono_reflection_cleanup_domain (domain);
1114
1115         /* This must be done before type_hash is freed */
1116         if (domain->class_vtable_array) {
1117                 int i;
1118                 for (i = 0; i < domain->class_vtable_array->len; ++i)
1119                         unregister_vtable_reflection_type ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
1120         }
1121
1122         if (domain->type_hash) {
1123                 mono_g_hash_table_destroy (domain->type_hash);
1124                 domain->type_hash = NULL;
1125         }
1126         if (domain->type_init_exception_hash) {
1127                 mono_g_hash_table_destroy (domain->type_init_exception_hash);
1128                 domain->type_init_exception_hash = NULL;
1129         }
1130
1131         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1132                 MonoAssembly *ass = (MonoAssembly *)tmp->data;
1133                 mono_assembly_release_gc_roots (ass);
1134         }
1135
1136         /* Have to zero out reference fields since they will be invalidated by the clear_domain () call below */
1137         for (p = (gpointer*)&domain->MONO_DOMAIN_FIRST_OBJECT; p < (gpointer*)&domain->MONO_DOMAIN_FIRST_GC_TRACKED; ++p)
1138                 *p = NULL;
1139
1140         /* This needs to be done before closing assemblies */
1141         mono_gc_clear_domain (domain);
1142
1143         /* Close dynamic assemblies first, since they have no ref count */
1144         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1145                 MonoAssembly *ass = (MonoAssembly *)tmp->data;
1146                 if (!ass->image || !image_is_dynamic (ass->image))
1147                         continue;
1148                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading domain %s[%p], assembly %s[%p], ref_count=%d", domain->friendly_name, domain, ass->aname.name, ass, ass->ref_count);
1149                 if (!mono_assembly_close_except_image_pools (ass))
1150                         tmp->data = NULL;
1151         }
1152
1153         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1154                 MonoAssembly *ass = (MonoAssembly *)tmp->data;
1155                 if (!ass)
1156                         continue;
1157                 if (!ass->image || image_is_dynamic (ass->image))
1158                         continue;
1159                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading domain %s[%p], assembly %s[%p], ref_count=%d", domain->friendly_name, domain, ass->aname.name, ass, ass->ref_count);
1160                 if (!mono_assembly_close_except_image_pools (ass))
1161                         tmp->data = NULL;
1162         }
1163
1164         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1165                 MonoAssembly *ass = (MonoAssembly *)tmp->data;
1166                 if (ass)
1167                         mono_assembly_close_finish (ass);
1168         }
1169         g_slist_free (domain->domain_assemblies);
1170         domain->domain_assemblies = NULL;
1171
1172         if (free_domain_hook)
1173                 free_domain_hook (domain);
1174
1175         /* FIXME: free delegate_hash_table when it's used */
1176         if (domain->search_path) {
1177                 g_strfreev (domain->search_path);
1178                 domain->search_path = NULL;
1179         }
1180         domain->create_proxy_for_type_method = NULL;
1181         domain->private_invoke_method = NULL;
1182         domain->default_context = NULL;
1183         domain->out_of_memory_ex = NULL;
1184         domain->null_reference_ex = NULL;
1185         domain->stack_overflow_ex = NULL;
1186         domain->ephemeron_tombstone = NULL;
1187         domain->entry_assembly = NULL;
1188
1189         g_free (domain->friendly_name);
1190         domain->friendly_name = NULL;
1191         g_ptr_array_free (domain->class_vtable_array, TRUE);
1192         domain->class_vtable_array = NULL;
1193         g_hash_table_destroy (domain->proxy_vtable_hash);
1194         domain->proxy_vtable_hash = NULL;
1195         if (domain->static_data_array) {
1196                 mono_gc_free_fixed (domain->static_data_array);
1197                 domain->static_data_array = NULL;
1198         }
1199         mono_internal_hash_table_destroy (&domain->jit_code_hash);
1200
1201         /*
1202          * There might still be jit info tables of this domain which
1203          * are not freed.  Since the domain cannot be in use anymore,
1204          * this will free them.
1205          */
1206         mono_thread_hazardous_try_free_all ();
1207         if (domain->aot_modules)
1208                 mono_jit_info_table_free (domain->aot_modules);
1209         g_assert (domain->num_jit_info_tables == 1);
1210         mono_jit_info_table_free (domain->jit_info_table);
1211         domain->jit_info_table = NULL;
1212         g_assert (!domain->jit_info_free_queue);
1213
1214         /* collect statistics */
1215         code_alloc = mono_code_manager_size (domain->code_mp, &code_size);
1216         total_domain_code_alloc += code_alloc;
1217         max_domain_code_alloc = MAX (max_domain_code_alloc, code_alloc);
1218         max_domain_code_size = MAX (max_domain_code_size, code_size);
1219
1220         if (debug_domain_unload) {
1221                 mono_mempool_invalidate (domain->mp);
1222                 mono_code_manager_invalidate (domain->code_mp);
1223         } else {
1224 #ifndef DISABLE_PERFCOUNTERS
1225                 mono_perfcounters->loader_bytes -= mono_mempool_get_allocated (domain->mp);
1226 #endif
1227                 mono_mempool_destroy (domain->mp);
1228                 domain->mp = NULL;
1229                 mono_code_manager_destroy (domain->code_mp);
1230                 domain->code_mp = NULL;
1231         }
1232         lock_free_mempool_free (domain->lock_free_mp);
1233         domain->lock_free_mp = NULL;
1234
1235         g_hash_table_destroy (domain->finalizable_objects_hash);
1236         domain->finalizable_objects_hash = NULL;
1237         if (domain->method_rgctx_hash) {
1238                 g_hash_table_destroy (domain->method_rgctx_hash);
1239                 domain->method_rgctx_hash = NULL;
1240         }
1241         if (domain->generic_virtual_cases) {
1242                 g_hash_table_destroy (domain->generic_virtual_cases);
1243                 domain->generic_virtual_cases = NULL;
1244         }
1245         if (domain->generic_virtual_thunks) {
1246                 g_hash_table_destroy (domain->generic_virtual_thunks);
1247                 domain->generic_virtual_thunks = NULL;
1248         }
1249         if (domain->ftnptrs_hash) {
1250                 g_hash_table_destroy (domain->ftnptrs_hash);
1251                 domain->ftnptrs_hash = NULL;
1252         }
1253         if (domain->method_to_dyn_method) {
1254                 g_hash_table_destroy (domain->method_to_dyn_method);
1255                 domain->method_to_dyn_method = NULL;
1256         }
1257
1258         mono_os_mutex_destroy (&domain->finalizable_objects_hash_lock);
1259         mono_os_mutex_destroy (&domain->assemblies_lock);
1260         mono_os_mutex_destroy (&domain->jit_code_hash_lock);
1261
1262         mono_coop_mutex_destroy (&domain->lock);
1263
1264         domain->setup = NULL;
1265
1266         mono_gc_deregister_root ((char*)&(domain->MONO_DOMAIN_FIRST_GC_TRACKED));
1267
1268         /* FIXME: anything else required ? */
1269
1270         mono_gc_free_fixed (domain);
1271
1272 #ifndef DISABLE_PERFCOUNTERS
1273         mono_perfcounters->loader_appdomains--;
1274 #endif
1275
1276         if (domain == mono_root_domain)
1277                 mono_root_domain = NULL;
1278 }
1279
1280 /**
1281  * mono_domain_get_by_id:
1282  * @domainid: the ID
1283  *
1284  * Returns: the domain for a specific domain id.
1285  */
1286 MonoDomain * 
1287 mono_domain_get_by_id (gint32 domainid) 
1288 {
1289         MonoDomain * domain;
1290
1291         mono_appdomains_lock ();
1292         if (domainid < appdomain_list_size)
1293                 domain = appdomains_list [domainid];
1294         else
1295                 domain = NULL;
1296         mono_appdomains_unlock ();
1297
1298         return domain;
1299 }
1300
1301 /*
1302  * mono_domain_get_id:
1303  *
1304  * A domain ID is guaranteed to be unique for as long as the domain
1305  * using it is alive. It may be reused later once the domain has been
1306  * unloaded.
1307  *
1308  * Returns: The unique ID for @domain.
1309  */
1310 gint32
1311 mono_domain_get_id (MonoDomain *domain)
1312 {
1313         return domain->domain_id;
1314 }
1315
1316 /*
1317  * mono_domain_get_friendly_name:
1318  *
1319  * The returned string's lifetime is the same as @domain's. Consider
1320  * copying it if you need to store it somewhere.
1321  *
1322  * Returns: The friendly name of @domain. Can be NULL if not yet set.
1323  */
1324 const char *
1325 mono_domain_get_friendly_name (MonoDomain *domain)
1326 {
1327         return domain->friendly_name;
1328 }
1329
1330 /*
1331  * mono_domain_alloc:
1332  *
1333  * LOCKING: Acquires the domain lock.
1334  */
1335 gpointer
1336 mono_domain_alloc (MonoDomain *domain, guint size)
1337 {
1338         gpointer res;
1339
1340         mono_domain_lock (domain);
1341 #ifndef DISABLE_PERFCOUNTERS
1342         mono_perfcounters->loader_bytes += size;
1343 #endif
1344         res = mono_mempool_alloc (domain->mp, size);
1345         mono_domain_unlock (domain);
1346
1347         return res;
1348 }
1349
1350 /*
1351  * mono_domain_alloc0:
1352  *
1353  * LOCKING: Acquires the domain lock.
1354  */
1355 gpointer
1356 mono_domain_alloc0 (MonoDomain *domain, guint size)
1357 {
1358         gpointer res;
1359
1360         mono_domain_lock (domain);
1361 #ifndef DISABLE_PERFCOUNTERS
1362         mono_perfcounters->loader_bytes += size;
1363 #endif
1364         res = mono_mempool_alloc0 (domain->mp, size);
1365         mono_domain_unlock (domain);
1366
1367         return res;
1368 }
1369
1370 gpointer
1371 mono_domain_alloc0_lock_free (MonoDomain *domain, guint size)
1372 {
1373         return lock_free_mempool_alloc0 (domain->lock_free_mp, size);
1374 }
1375
1376 /*
1377  * mono_domain_code_reserve:
1378  *
1379  * LOCKING: Acquires the domain lock.
1380  */
1381 void*
1382 mono_domain_code_reserve (MonoDomain *domain, int size)
1383 {
1384         gpointer res;
1385
1386         mono_domain_lock (domain);
1387         res = mono_code_manager_reserve (domain->code_mp, size);
1388         mono_domain_unlock (domain);
1389
1390         return res;
1391 }
1392
1393 /*
1394  * mono_domain_code_reserve_align:
1395  *
1396  * LOCKING: Acquires the domain lock.
1397  */
1398 void*
1399 mono_domain_code_reserve_align (MonoDomain *domain, int size, int alignment)
1400 {
1401         gpointer res;
1402
1403         mono_domain_lock (domain);
1404         res = mono_code_manager_reserve_align (domain->code_mp, size, alignment);
1405         mono_domain_unlock (domain);
1406
1407         return res;
1408 }
1409
1410 /*
1411  * mono_domain_code_commit:
1412  *
1413  * LOCKING: Acquires the domain lock.
1414  */
1415 void
1416 mono_domain_code_commit (MonoDomain *domain, void *data, int size, int newsize)
1417 {
1418         mono_domain_lock (domain);
1419         mono_code_manager_commit (domain->code_mp, data, size, newsize);
1420         mono_domain_unlock (domain);
1421 }
1422
1423 /*
1424  * mono_domain_code_foreach:
1425  * Iterate over the code thunks of the code manager of @domain.
1426  * 
1427  * The @func callback MUST not take any locks. If it really needs to, it must respect
1428  * the locking rules of the runtime: http://www.mono-project.com/Mono:Runtime:Documentation:ThreadSafety 
1429  * LOCKING: Acquires the domain lock.
1430  */
1431
1432 void
1433 mono_domain_code_foreach (MonoDomain *domain, MonoCodeManagerFunc func, void *user_data)
1434 {
1435         mono_domain_lock (domain);
1436         mono_code_manager_foreach (domain->code_mp, func, user_data);
1437         mono_domain_unlock (domain);
1438 }
1439
1440
1441 void 
1442 mono_context_set (MonoAppContext * new_context)
1443 {
1444         SET_APPCONTEXT (new_context);
1445 }
1446
1447 /**
1448  * mono_context_get:
1449  *
1450  * Returns: the current Mono Application Context.
1451  */
1452 MonoAppContext * 
1453 mono_context_get (void)
1454 {
1455         return GET_APPCONTEXT ();
1456 }
1457
1458 /**
1459  * mono_context_get_id:
1460  * @context: the context to operate on.
1461  *
1462  * Context IDs are guaranteed to be unique for the duration of a Mono
1463  * process; they are never reused.
1464  *
1465  * Returns: The unique ID for @context.
1466  */
1467 gint32
1468 mono_context_get_id (MonoAppContext *context)
1469 {
1470         return context->context_id;
1471 }
1472
1473 /**
1474  * mono_context_get_domain_id:
1475  * @context: the context to operate on.
1476  *
1477  * Returns: The ID of the domain that @context was created in.
1478  */
1479 gint32
1480 mono_context_get_domain_id (MonoAppContext *context)
1481 {
1482         return context->domain_id;
1483 }
1484
1485 /* LOCKING: the caller holds the lock for this domain */
1486 void
1487 mono_domain_add_class_static_data (MonoDomain *domain, MonoClass *klass, gpointer data, guint32 *bitmap)
1488 {
1489         /* Note [Domain Static Data Array]:
1490          *
1491          * Entry 0 in the array is the index of the next free slot.
1492          * Entry 1 is the total size of the array.
1493          */
1494         int next;
1495         if (domain->static_data_array) {
1496                 int size = GPOINTER_TO_INT (domain->static_data_array [1]);
1497                 next = GPOINTER_TO_INT (domain->static_data_array [0]);
1498                 if (next >= size) {
1499                         /* 'data' is allocated by alloc_fixed */
1500                         gpointer *new_array = (gpointer *)mono_gc_alloc_fixed (sizeof (gpointer) * (size * 2), MONO_GC_ROOT_DESCR_FOR_FIXED (size * 2), MONO_ROOT_SOURCE_DOMAIN, "static field list");
1501                         mono_gc_memmove_aligned (new_array, domain->static_data_array, sizeof (gpointer) * size);
1502                         size *= 2;
1503                         new_array [1] = GINT_TO_POINTER (size);
1504                         mono_gc_free_fixed (domain->static_data_array);
1505                         domain->static_data_array = new_array;
1506                 }
1507         } else {
1508                 int size = 32;
1509                 gpointer *new_array = (gpointer *)mono_gc_alloc_fixed (sizeof (gpointer) * size, MONO_GC_ROOT_DESCR_FOR_FIXED (size), MONO_ROOT_SOURCE_DOMAIN, "static field list");
1510                 next = 2;
1511                 new_array [0] = GINT_TO_POINTER (next);
1512                 new_array [1] = GINT_TO_POINTER (size);
1513                 domain->static_data_array = new_array;
1514         }
1515         domain->static_data_array [next++] = data;
1516         domain->static_data_array [0] = GINT_TO_POINTER (next);
1517 }
1518
1519 /**
1520  * mono_get_corlib:
1521  *
1522  * Use this function to get the `MonoImage*` for the mscorlib.dll assembly
1523  *
1524  * Returns: The MonoImage for mscorlib.dll
1525  */
1526 MonoImage*
1527 mono_get_corlib (void)
1528 {
1529         return mono_defaults.corlib;
1530 }
1531
1532 /**
1533  * mono_get_object_class:
1534  *
1535  * Use this function to get the `MonoClass*` that the runtime is using for `System.Object`.
1536  *
1537  * Returns: The `MonoClass*` for the `System.Object` type.
1538  */
1539 MonoClass*
1540 mono_get_object_class (void)
1541 {
1542         return mono_defaults.object_class;
1543 }
1544
1545 /**
1546  * mono_get_byte_class:
1547  *
1548  * Use this function to get the `MonoClass*` that the runtime is using for `System.Byte`.
1549  *
1550  * Returns: The `MonoClass*` for the `System.Byte` type.
1551  */
1552 MonoClass*
1553 mono_get_byte_class (void)
1554 {
1555         return mono_defaults.byte_class;
1556 }
1557
1558 /**
1559  * mono_get_void_class:
1560  *
1561  * Use this function to get the `MonoClass*` that the runtime is using for `System.Void`.
1562  *
1563  * Returns: The `MonoClass*` for the `System.Void` type.
1564  */
1565 MonoClass*
1566 mono_get_void_class (void)
1567 {
1568         return mono_defaults.void_class;
1569 }
1570
1571 /**
1572  * mono_get_boolean_class:
1573  *
1574  * Use this function to get the `MonoClass*` that the runtime is using for `System.Boolean`.
1575  *
1576  * Returns: The `MonoClass*` for the `System.Boolean` type.
1577  */
1578 MonoClass*
1579 mono_get_boolean_class (void)
1580 {
1581         return mono_defaults.boolean_class;
1582 }
1583
1584 /**
1585  * mono_get_sbyte_class:
1586  *
1587  * Use this function to get the `MonoClass*` that the runtime is using for `System.SByte`.
1588  *
1589  * Returns: The `MonoClass*` for the `System.SByte` type.
1590  */
1591 MonoClass*
1592 mono_get_sbyte_class (void)
1593 {
1594         return mono_defaults.sbyte_class;
1595 }
1596
1597 /**
1598  * mono_get_int16_class:
1599  *
1600  * Use this function to get the `MonoClass*` that the runtime is using for `System.Int16`.
1601  *
1602  * Returns: The `MonoClass*` for the `System.Int16` type.
1603  */
1604 MonoClass*
1605 mono_get_int16_class (void)
1606 {
1607         return mono_defaults.int16_class;
1608 }
1609
1610 /**
1611  * mono_get_uint16_class:
1612  *
1613  * Use this function to get the `MonoClass*` that the runtime is using for `System.UInt16`.
1614  *
1615  * Returns: The `MonoClass*` for the `System.UInt16` type.
1616  */
1617 MonoClass*
1618 mono_get_uint16_class (void)
1619 {
1620         return mono_defaults.uint16_class;
1621 }
1622
1623 /**
1624  * mono_get_int32_class:
1625  *
1626  * Use this function to get the `MonoClass*` that the runtime is using for `System.Int32`.
1627  *
1628  * Returns: The `MonoClass*` for the `System.Int32` type.
1629  */
1630 MonoClass*
1631 mono_get_int32_class (void)
1632 {
1633         return mono_defaults.int32_class;
1634 }
1635
1636 /**
1637  * mono_get_uint32_class:
1638  *
1639  * Use this function to get the `MonoClass*` that the runtime is using for `System.UInt32`.
1640  *
1641  * Returns: The `MonoClass*` for the `System.UInt32` type.
1642  */
1643 MonoClass*
1644 mono_get_uint32_class (void)
1645 {
1646         return mono_defaults.uint32_class;
1647 }
1648
1649 /**
1650  * mono_get_intptr_class:
1651  *
1652  * Use this function to get the `MonoClass*` that the runtime is using for `System.IntPtr`.
1653  *
1654  * Returns: The `MonoClass*` for the `System.IntPtr` type.
1655  */
1656 MonoClass*
1657 mono_get_intptr_class (void)
1658 {
1659         return mono_defaults.int_class;
1660 }
1661
1662 /**
1663  * mono_get_uintptr_class:
1664  *
1665  * Use this function to get the `MonoClass*` that the runtime is using for `System.UIntPtr`.
1666  *
1667  * Returns: The `MonoClass*` for the `System.UIntPtr` type.
1668  */
1669 MonoClass*
1670 mono_get_uintptr_class (void)
1671 {
1672         return mono_defaults.uint_class;
1673 }
1674
1675 /**
1676  * mono_get_int64_class:
1677  *
1678  * Use this function to get the `MonoClass*` that the runtime is using for `System.Int64`.
1679  *
1680  * Returns: The `MonoClass*` for the `System.Int64` type.
1681  */
1682 MonoClass*
1683 mono_get_int64_class (void)
1684 {
1685         return mono_defaults.int64_class;
1686 }
1687
1688 /**
1689  * mono_get_uint64_class:
1690  *
1691  * Use this function to get the `MonoClass*` that the runtime is using for `System.UInt64`.
1692  *
1693  * Returns: The `MonoClass*` for the `System.UInt64` type.
1694  */
1695 MonoClass*
1696 mono_get_uint64_class (void)
1697 {
1698         return mono_defaults.uint64_class;
1699 }
1700
1701 /**
1702  * mono_get_single_class:
1703  *
1704  * Use this function to get the `MonoClass*` that the runtime is using for `System.Single` (32-bit floating points).
1705  *
1706  * Returns: The `MonoClass*` for the `System.Single` type.
1707  */
1708 MonoClass*
1709 mono_get_single_class (void)
1710 {
1711         return mono_defaults.single_class;
1712 }
1713
1714 /**
1715  * mono_get_double_class:
1716  *
1717  * Use this function to get the `MonoClass*` that the runtime is using for `System.Double` (64-bit floating points).
1718  *
1719  * Returns: The `MonoClass*` for the `System.Double` type.
1720  */
1721 MonoClass*
1722 mono_get_double_class (void)
1723 {
1724         return mono_defaults.double_class;
1725 }
1726
1727 /**
1728  * mono_get_char_class:
1729  *
1730  * Use this function to get the `MonoClass*` that the runtime is using for `System.Char`.
1731  *
1732  * Returns: The `MonoClass*` for the `System.Char` type.
1733  */
1734 MonoClass*
1735 mono_get_char_class (void)
1736 {
1737         return mono_defaults.char_class;
1738 }
1739
1740 /**
1741  * mono_get_string_class:
1742  *
1743  * Use this function to get the `MonoClass*` that the runtime is using for `System.String`.
1744  *
1745  * Returns: The `MonoClass*` for the `System.String` type.
1746  */
1747 MonoClass*
1748 mono_get_string_class (void)
1749 {
1750         return mono_defaults.string_class;
1751 }
1752
1753 /**
1754  * mono_get_enum_class:
1755  *
1756  * Use this function to get the `MonoClass*` that the runtime is using for `System.Enum`.
1757  *
1758  * Returns: The `MonoClass*` for the `System.Enum` type.
1759  */
1760 MonoClass*
1761 mono_get_enum_class (void)
1762 {
1763         return mono_defaults.enum_class;
1764 }
1765
1766 /**
1767  * mono_get_array_class:
1768  *
1769  * Use this function to get the `MonoClass*` that the runtime is using for `System.Array`.
1770  *
1771  * Returns: The `MonoClass*` for the `System.Array` type.
1772  */
1773 MonoClass*
1774 mono_get_array_class (void)
1775 {
1776         return mono_defaults.array_class;
1777 }
1778
1779 /**
1780  * mono_get_thread_class:
1781  *
1782  * Use this function to get the `MonoClass*` that the runtime is using for `System.Threading.Thread`.
1783  *
1784  * Returns: The `MonoClass*` for the `System.Threading.Thread` type.
1785  */
1786 MonoClass*
1787 mono_get_thread_class (void)
1788 {
1789         return mono_defaults.thread_class;
1790 }
1791
1792 /**
1793  * mono_get_exception_class:
1794  *
1795  * Use this function to get the `MonoClass*` that the runtime is using for `System.Exception`.
1796  *
1797  * Returns: The `MonoClass*` for the `` type.
1798  */
1799 MonoClass*
1800 mono_get_exception_class (void)
1801 {
1802         return mono_defaults.exception_class;
1803 }
1804
1805
1806 static char* get_attribute_value (const gchar **attribute_names, 
1807                                         const gchar **attribute_values, 
1808                                         const char *att_name)
1809 {
1810         int n;
1811         for (n=0; attribute_names[n] != NULL; n++) {
1812                 if (strcmp (attribute_names[n], att_name) == 0)
1813                         return g_strdup (attribute_values[n]);
1814         }
1815         return NULL;
1816 }
1817
1818 static void start_element (GMarkupParseContext *context, 
1819                            const gchar         *element_name,
1820                            const gchar        **attribute_names,
1821                            const gchar        **attribute_values,
1822                            gpointer             user_data,
1823                            GError             **error)
1824 {
1825         AppConfigInfo* app_config = (AppConfigInfo*) user_data;
1826         
1827         if (strcmp (element_name, "configuration") == 0) {
1828                 app_config->configuration_count++;
1829                 return;
1830         }
1831         if (strcmp (element_name, "startup") == 0) {
1832                 app_config->startup_count++;
1833                 return;
1834         }
1835         
1836         if (app_config->configuration_count != 1 || app_config->startup_count != 1)
1837                 return;
1838         
1839         if (strcmp (element_name, "requiredRuntime") == 0) {
1840                 app_config->required_runtime = get_attribute_value (attribute_names, attribute_values, "version");
1841         } else if (strcmp (element_name, "supportedRuntime") == 0) {
1842                 char *version = get_attribute_value (attribute_names, attribute_values, "version");
1843                 app_config->supported_runtimes = g_slist_append (app_config->supported_runtimes, version);
1844         }
1845 }
1846
1847 static void end_element   (GMarkupParseContext *context,
1848                            const gchar         *element_name,
1849                            gpointer             user_data,
1850                            GError             **error)
1851 {
1852         AppConfigInfo* app_config = (AppConfigInfo*) user_data;
1853         
1854         if (strcmp (element_name, "configuration") == 0) {
1855                 app_config->configuration_count--;
1856         } else if (strcmp (element_name, "startup") == 0) {
1857                 app_config->startup_count--;
1858         }
1859 }
1860
1861 static const GMarkupParser 
1862 mono_parser = {
1863         start_element,
1864         end_element,
1865         NULL,
1866         NULL,
1867         NULL
1868 };
1869
1870 static AppConfigInfo *
1871 app_config_parse (const char *exe_filename)
1872 {
1873         AppConfigInfo *app_config;
1874         GMarkupParseContext *context;
1875         char *text;
1876         gsize len;
1877         const char *bundled_config;
1878         char *config_filename;
1879
1880         bundled_config = mono_config_string_for_assembly_file (exe_filename);
1881
1882         if (bundled_config) {
1883                 text = g_strdup (bundled_config);
1884                 len = strlen (text);
1885         } else {
1886                 config_filename = g_strconcat (exe_filename, ".config", NULL);
1887
1888                 if (!g_file_get_contents (config_filename, &text, &len, NULL)) {
1889                         g_free (config_filename);
1890                         return NULL;
1891                 }
1892                 g_free (config_filename);
1893         }
1894
1895         app_config = g_new0 (AppConfigInfo, 1);
1896
1897         context = g_markup_parse_context_new (&mono_parser, (GMarkupParseFlags)0, app_config, NULL);
1898         if (g_markup_parse_context_parse (context, text, len, NULL)) {
1899                 g_markup_parse_context_end_parse (context, NULL);
1900         }
1901         g_markup_parse_context_free (context);
1902         g_free (text);
1903         return app_config;
1904 }
1905
1906 static void 
1907 app_config_free (AppConfigInfo* app_config)
1908 {
1909         char *rt;
1910         GSList *list = app_config->supported_runtimes;
1911         while (list != NULL) {
1912                 rt = (char*)list->data;
1913                 g_free (rt);
1914                 list = g_slist_next (list);
1915         }
1916         g_slist_free (app_config->supported_runtimes);
1917         g_free (app_config->required_runtime);
1918         g_free (app_config);
1919 }
1920
1921
1922 static const MonoRuntimeInfo*
1923 get_runtime_by_version (const char *version)
1924 {
1925         int n;
1926         int max = G_N_ELEMENTS (supported_runtimes);
1927         int vlen;
1928
1929         if (!version)
1930                 return NULL;
1931
1932         for (n=0; n<max; n++) {
1933                 if (strcmp (version, supported_runtimes[n].runtime_version) == 0)
1934                         return &supported_runtimes[n];
1935         }
1936         
1937         vlen = strlen (version);
1938         if (vlen >= 4 && version [1] - '0' >= 4) {
1939                 for (n=0; n<max; n++) {
1940                         if (strncmp (version, supported_runtimes[n].runtime_version, 4) == 0)
1941                                 return &supported_runtimes[n];
1942                 }
1943         }
1944         
1945         return NULL;
1946 }
1947
1948 static void
1949 get_runtimes_from_exe (const char *exe_file, MonoImage **exe_image, const MonoRuntimeInfo** runtimes)
1950 {
1951         AppConfigInfo* app_config;
1952         char *version;
1953         const MonoRuntimeInfo* runtime = NULL;
1954         MonoImage *image = NULL;
1955         
1956         app_config = app_config_parse (exe_file);
1957         
1958         if (app_config != NULL) {
1959                 /* Check supportedRuntime elements, if none is supported, fail.
1960                  * If there are no such elements, look for a requiredRuntime element.
1961                  */
1962                 if (app_config->supported_runtimes != NULL) {
1963                         int n = 0;
1964                         GSList *list = app_config->supported_runtimes;
1965                         while (list != NULL) {
1966                                 version = (char*) list->data;
1967                                 runtime = get_runtime_by_version (version);
1968                                 if (runtime != NULL)
1969                                         runtimes [n++] = runtime;
1970                                 list = g_slist_next (list);
1971                         }
1972                         runtimes [n] = NULL;
1973                         app_config_free (app_config);
1974                         return;
1975                 }
1976                 
1977                 /* Check the requiredRuntime element. This is for 1.0 apps only. */
1978                 if (app_config->required_runtime != NULL) {
1979                         runtimes [0] = get_runtime_by_version (app_config->required_runtime);
1980                         runtimes [1] = NULL;
1981                         app_config_free (app_config);
1982                         return;
1983                 }
1984                 app_config_free (app_config);
1985         }
1986         
1987         /* Look for a runtime with the exact version */
1988         image = mono_assembly_open_from_bundle (exe_file, NULL, FALSE);
1989
1990         if (image == NULL)
1991                 image = mono_image_open (exe_file, NULL);
1992
1993         if (image == NULL) {
1994                 /* The image is wrong or the file was not found. In this case return
1995                  * a default runtime and leave to the initialization method the work of
1996                  * reporting the error.
1997                  */
1998                 runtimes [0] = get_runtime_by_version (DEFAULT_RUNTIME_VERSION);
1999                 runtimes [1] = NULL;
2000                 return;
2001         }
2002
2003         *exe_image = image;
2004
2005         runtimes [0] = get_runtime_by_version (image->version);
2006         runtimes [1] = NULL;
2007 }
2008
2009
2010 /**
2011  * mono_get_runtime_info:
2012  *
2013  * Returns: the version of the current runtime instance.
2014  */
2015 const MonoRuntimeInfo*
2016 mono_get_runtime_info (void)
2017 {
2018         return current_runtime;
2019 }
2020
2021 /**
2022  * mono_framework_version:
2023  *
2024  * Return the major version of the framework curently executing.
2025  */
2026 int
2027 mono_framework_version (void)
2028 {
2029         return current_runtime->framework_version [0] - '0';
2030 }
2031
2032 void
2033 mono_enable_debug_domain_unload (gboolean enable)
2034 {
2035         debug_domain_unload = enable;
2036 }
2037
2038 MonoAotCacheConfig *
2039 mono_get_aot_cache_config (void)
2040 {
2041         return &aot_cache_config;
2042 }
2043
2044 void
2045 mono_domain_lock (MonoDomain *domain)
2046 {
2047         mono_locks_coop_acquire (&domain->lock, DomainLock);
2048 }
2049
2050 void
2051 mono_domain_unlock (MonoDomain *domain)
2052 {
2053         mono_locks_coop_release (&domain->lock, DomainLock);
2054 }