[boehm] Integrate toggleref support into the runtime.
[mono.git] / mono / metadata / domain.c
index 66bebd13c88c292d8d00fdd5f8c077d7cadb29c0..447e860164654c913ca0d35a916a283a97728594 100644 (file)
 
 #include <mono/metadata/gc-internal.h>
 
+#include <mono/utils/atomic.h>
 #include <mono/utils/mono-compiler.h>
 #include <mono/utils/mono-logger-internal.h>
 #include <mono/utils/mono-membar.h>
 #include <mono/utils/mono-counters.h>
 #include <mono/utils/hazard-pointer.h>
 #include <mono/utils/mono-tls.h>
+#include <mono/utils/mono-mmap.h>
+#include <mono/utils/mono-threads.h>
 #include <mono/metadata/object.h>
 #include <mono/metadata/object-internals.h>
 #include <mono/metadata/domain-internals.h>
 #include <mono/metadata/mono-debug-debugger.h>
 #include <mono/metadata/mono-config.h>
 #include <mono/metadata/threads-types.h>
+#include <mono/metadata/runtime.h>
 #include <metadata/threads.h>
 #include <metadata/profiler-private.h>
 #include <mono/metadata/coree.h>
 
-/* #define DEBUG_DOMAIN_UNLOAD */
+//#define DEBUG_DOMAIN_UNLOAD 1
 
 /* we need to use both the Tls* functions and __thread because
  * some archs may generate faster jit code with one meachanism
@@ -55,17 +59,25 @@ MONO_FAST_TLS_DECLARE(tls_appdomain);
 #define GET_APPDOMAIN() ((MonoDomain*)MONO_FAST_TLS_GET(tls_appdomain))
 
 #define SET_APPDOMAIN(x) do { \
+       MonoThreadInfo *info; \
        MONO_FAST_TLS_SET (tls_appdomain,x); \
        mono_native_tls_set_value (appdomain_thread_id, x); \
        mono_gc_set_current_thread_appdomain (x); \
+       info = mono_thread_info_current (); \
+       if (info) \
+               mono_thread_info_tls_set (info, TLS_KEY_DOMAIN, (x));   \
 } while (FALSE)
 
 #else /* !MONO_HAVE_FAST_TLS */
 
 #define GET_APPDOMAIN() ((MonoDomain *)mono_native_tls_get_value (appdomain_thread_id))
 #define SET_APPDOMAIN(x) do {                                          \
+               MonoThreadInfo *info;                                                           \
                mono_native_tls_set_value (appdomain_thread_id, x);     \
                mono_gc_set_current_thread_appdomain (x);               \
+               info = mono_thread_info_current ();                             \
+               if (info)                                                                                                \
+                       mono_thread_info_tls_set (info, TLS_KEY_DOMAIN, (x));   \
        } while (FALSE)
 
 #endif
@@ -101,32 +113,20 @@ typedef struct {
        int startup_count;
 } AppConfigInfo;
 
-/*
- * AotModuleInfo: Contains information about AOT modules.
- */
-typedef struct {
-       MonoImage *image;
-       gpointer start, end;
-} AotModuleInfo;
-
 static const MonoRuntimeInfo *current_runtime = NULL;
 
 static MonoJitInfoFindInAot jit_info_find_in_aot_func = NULL;
 
-/*
- * Contains information about AOT loaded code.
- */
-static MonoAotModuleInfoTable *aot_modules = NULL;
-
 /* This is the list of runtime versions supported by this JIT.
  */
 static const MonoRuntimeInfo supported_runtimes[] = {
-       {"v2.0.50215","2.0", { {2,0,0,0},    {8,0,0,0}, { 3, 5, 0, 0 } }        },
-       {"v2.0.50727","2.0", { {2,0,0,0},    {8,0,0,0}, { 3, 5, 0, 0 } }        },
-       {"v4.0.30319","4.5", { {4,0,0,0},    {10,0,0,0}, { 4, 0, 0, 0 } }   },
-       {"v4.0.30128","4.0", { {4,0,0,0},    {10,0,0,0}, { 4, 0, 0, 0 } }   },
-       {"v4.0.20506","4.0", { {4,0,0,0},    {10,0,0,0}, { 4, 0, 0, 0 } }   },
-       {"moonlight", "2.1", { {2,0,5,0},    {9,0,0,0}, { 3, 5, 0, 0 } }    },
+       {"v2.0.50215","2.0", { {2,0,0,0}, { 8,0,0,0}, {3,5,0,0}, {3,0,0,0} } },
+       {"v2.0.50727","2.0", { {2,0,0,0}, { 8,0,0,0}, {3,5,0,0}, {3,0,0,0} } },
+       {"v4.0.30319","4.5", { {4,0,0,0}, {10,0,0,0}, {4,0,0,0}, {4,0,0,0} } },
+       {"v4.0.30128","4.0", { {4,0,0,0}, {10,0,0,0}, {4,0,0,0}, {4,0,0,0} } },
+       {"v4.0.20506","4.0", { {4,0,0,0}, {10,0,0,0}, {4,0,0,0}, {4,0,0,0} } },
+       {"mobile",    "2.1", { {2,0,5,0}, {10,0,0,0}, {2,0,5,0}, {2,0,5,0} } },
+       {"moonlight", "2.1", { {2,0,5,0}, { 9,0,0,0}, {3,5,0,0}, {3,0,0,0} } },
 };
 
 
@@ -146,9 +146,6 @@ get_runtimes_from_exe (const char *exe_file, MonoImage **exe_image, const MonoRu
 static const MonoRuntimeInfo*
 get_runtime_by_version (const char *version);
 
-static MonoImage*
-mono_jit_info_find_aot_module (guint8* addr);
-
 MonoNativeTlsKey
 mono_domain_get_tls_key (void)
 {
@@ -173,7 +170,7 @@ mono_domain_get_tls_offset (void)
 #define JIT_INFO_TABLE_HIGH_WATERMARK(n)       ((n) * 5 / 6)
 
 #define JIT_INFO_TOMBSTONE_MARKER      ((MonoMethod*)NULL)
-#define IS_JIT_INFO_TOMBSTONE(ji)      ((ji)->method == JIT_INFO_TOMBSTONE_MARKER)
+#define IS_JIT_INFO_TOMBSTONE(ji)      ((ji)->d.method == JIT_INFO_TOMBSTONE_MARKER)
 
 #define JIT_INFO_TABLE_HAZARD_INDEX            0
 #define JIT_INFO_HAZARD_INDEX                  1
@@ -330,26 +327,11 @@ jit_info_table_chunk_index (MonoJitInfoTableChunk *chunk, MonoThreadHazardPointe
        return left;
 }
 
-MonoJitInfo*
-mono_jit_info_table_find (MonoDomain *domain, char *addr)
+static MonoJitInfo*
+jit_info_table_find (MonoJitInfoTable *table, MonoThreadHazardPointers *hp, gint8 *addr)
 {
-       MonoJitInfoTable *table;
        MonoJitInfo *ji;
        int chunk_pos, pos;
-       MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
-       MonoImage *image;
-
-       ++mono_stats.jit_info_table_lookup_count;
-
-       /* First we have to get the domain's jit_info_table.  This is
-          complicated by the fact that a writer might substitute a
-          new table and free the old one.  What the writer guarantees
-          us is that it looks at the hazard pointers after it has
-          changed the jit_info_table pointer.  So, if we guard the
-          table by a hazard pointer and make sure that the pointer is
-          still there after we've made it hazardous, we don't have to
-          worry about the writer freeing the table. */
-       table = get_hazardous_pointer ((gpointer volatile*)&domain->jit_info_table, hp, JIT_INFO_TABLE_HAZARD_INDEX);
 
        chunk_pos = jit_info_table_index (table, (gint8*)addr);
        g_assert (chunk_pos < table->num_chunks);
@@ -375,7 +357,6 @@ mono_jit_info_table_find (MonoDomain *domain, char *addr)
                        }
                        if ((gint8*)addr >= (gint8*)ji->code_start
                                        && (gint8*)addr < (gint8*)ji->code_start + ji->code_size) {
-                               mono_hazard_pointer_clear (hp, JIT_INFO_TABLE_HAZARD_INDEX);
                                mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
                                return ji;
                        }
@@ -392,22 +373,64 @@ mono_jit_info_table_find (MonoDomain *domain, char *addr)
        } while (chunk_pos < table->num_chunks);
 
  not_found:
-       if (!hp)
-               return NULL;
+       if (hp)
+               mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
+       return NULL;
+}
+
+/*
+ * mono_jit_info_table_find_internal:
+ *
+ * If TRY_AOT is FALSE, avoid loading information for missing methods from AOT images, which is currently not async safe.
+ * In this case, only those AOT methods will be found whose jit info is already loaded.
+ * ASYNC SAFETY: When called in an async context (mono_thread_info_is_async_context ()), this is async safe.
+ * In this case, the returned MonoJitInfo might not have metadata information, in particular,
+ * mono_jit_info_get_method () could fail.
+ */
+MonoJitInfo*
+mono_jit_info_table_find_internal (MonoDomain *domain, char *addr, gboolean try_aot)
+{
+       MonoJitInfoTable *table;
+       MonoJitInfo *ji, *module_ji;
+       MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
 
-       mono_hazard_pointer_clear (hp, JIT_INFO_TABLE_HAZARD_INDEX);
-       mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
+       ++mono_stats.jit_info_table_lookup_count;
 
-       ji = NULL;
+       /* First we have to get the domain's jit_info_table.  This is
+          complicated by the fact that a writer might substitute a
+          new table and free the old one.  What the writer guarantees
+          us is that it looks at the hazard pointers after it has
+          changed the jit_info_table pointer.  So, if we guard the
+          table by a hazard pointer and make sure that the pointer is
+          still there after we've made it hazardous, we don't have to
+          worry about the writer freeing the table. */
+       table = get_hazardous_pointer ((gpointer volatile*)&domain->jit_info_table, hp, JIT_INFO_TABLE_HAZARD_INDEX);
+
+       ji = jit_info_table_find (table, hp, (gint8*)addr);
+       if (hp)
+               mono_hazard_pointer_clear (hp, JIT_INFO_TABLE_HAZARD_INDEX);
+       if (ji)
+               return ji;
 
        /* Maybe its an AOT module */
-       image = mono_jit_info_find_aot_module ((guint8*)addr);
-       if (image)
-               ji = jit_info_find_in_aot_func (domain, image, addr);
+       if (try_aot && mono_root_domain && mono_root_domain->aot_modules) {
+               table = get_hazardous_pointer ((gpointer volatile*)&mono_root_domain->aot_modules, hp, JIT_INFO_TABLE_HAZARD_INDEX);
+               module_ji = jit_info_table_find (table, hp, (gint8*)addr);
+               if (module_ji)
+                       ji = jit_info_find_in_aot_func (domain, module_ji->d.image, addr);
+               if (hp)
+                       mono_hazard_pointer_clear (hp, JIT_INFO_TABLE_HAZARD_INDEX);
+       }
        
        return ji;
 }
 
+MonoJitInfo*
+mono_jit_info_table_find (MonoDomain *domain, char *addr)
+{
+       return mono_jit_info_table_find_internal (domain, addr, TRUE);
+}
+
 static G_GNUC_UNUSED void
 jit_info_table_check (MonoJitInfoTable *table)
 {
@@ -463,6 +486,11 @@ jit_info_table_realloc (MonoJitInfoTable *old)
        /* number of needed places for elements needed */
        required_size = (int)((long)num_elements * JIT_INFO_TABLE_FILL_RATIO_DENOM / JIT_INFO_TABLE_FILL_RATIO_NOM);
        num_chunks = (required_size + MONO_JIT_INFO_TABLE_CHUNK_SIZE - 1) / MONO_JIT_INFO_TABLE_CHUNK_SIZE;
+       if (num_chunks == 0) {
+               g_assert (num_elements == 0);
+               return jit_info_table_new (old->domain);
+       }
+       g_assert (num_chunks > 0);
 
        new = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE + sizeof (MonoJitInfoTableChunk*) * num_chunks);
        new->domain = old->domain;
@@ -659,22 +687,16 @@ jit_info_table_chunk_overflow (MonoJitInfoTable *table, MonoJitInfoTableChunk *c
  * the one we're looking for (i.e. we either find the element directly
  * or we end up to the left of it).
  */
-void
-mono_jit_info_table_add (MonoDomain *domain, MonoJitInfo *ji)
+static void
+jit_info_table_add (MonoDomain *domain, MonoJitInfoTable *volatile *table_ptr, MonoJitInfo *ji)
 {
        MonoJitInfoTable *table;
-       int chunk_pos, pos;
        MonoJitInfoTableChunk *chunk;
+       int chunk_pos, pos;
        int num_elements;
        int i;
 
-       g_assert (ji->method != NULL);
-
-       mono_domain_lock (domain);
-
-       ++mono_stats.jit_info_table_insert_count;
-
-       table = domain->jit_info_table;
+       table = *table_ptr;
 
  restart:
        chunk_pos = jit_info_table_index (table, (gint8*)ji->code_start + ji->code_size);
@@ -687,10 +709,10 @@ mono_jit_info_table_add (MonoDomain *domain, MonoJitInfo *ji)
                /* Debugging code, should be removed. */
                //jit_info_table_check (new_table);
 
-               domain->jit_info_table = new_table;
+               *table_ptr = new_table;
                mono_memory_barrier ();
                domain->num_jit_info_tables++;
-               mono_thread_hazardous_free_or_queue (table, (MonoHazardousFreeFunc)jit_info_table_free);
+               mono_thread_hazardous_free_or_queue (table, (MonoHazardousFreeFunc)jit_info_table_free, TRUE, FALSE);
                table = new_table;
 
                goto restart;
@@ -729,6 +751,18 @@ mono_jit_info_table_add (MonoDomain *domain, MonoJitInfo *ji)
 
        /* Debugging code, should be removed. */
        //jit_info_table_check (table);
+}
+
+void
+mono_jit_info_table_add (MonoDomain *domain, MonoJitInfo *ji)
+{
+       g_assert (ji->d.method != NULL);
+
+       mono_domain_lock (domain);
+
+       ++mono_stats.jit_info_table_insert_count;
+
+       jit_info_table_add (domain, &domain->jit_info_table, ji);
 
        mono_domain_unlock (domain);
 }
@@ -740,7 +774,7 @@ mono_jit_info_make_tombstone (MonoJitInfo *ji)
 
        tombstone->code_start = ji->code_start;
        tombstone->code_size = ji->code_size;
-       tombstone->method = JIT_INFO_TOMBSTONE_MARKER;
+       tombstone->d.method = JIT_INFO_TOMBSTONE_MARKER;
 
        return tombstone;
 }
@@ -754,25 +788,19 @@ mono_jit_info_free_or_queue (MonoDomain *domain, MonoJitInfo *ji)
        if (domain->num_jit_info_tables <= 1) {
                /* Can it actually happen that we only have one table
                   but ji is still hazardous? */
-               mono_thread_hazardous_free_or_queue (ji, g_free);
+               mono_thread_hazardous_free_or_queue (ji, g_free, TRUE, FALSE);
        } else {
                domain->jit_info_free_queue = g_slist_prepend (domain->jit_info_free_queue, ji);
        }
 }
 
-void
-mono_jit_info_table_remove (MonoDomain *domain, MonoJitInfo *ji)
+static void
+jit_info_table_remove (MonoJitInfoTable *table, MonoJitInfo *ji)
 {
-       MonoJitInfoTable *table;
        MonoJitInfoTableChunk *chunk;
        gpointer start = ji->code_start;
        int chunk_pos, pos;
 
-       mono_domain_lock (domain);
-       table = domain->jit_info_table;
-
-       ++mono_stats.jit_info_table_remove_count;
-
        chunk_pos = jit_info_table_index (table, start);
        g_assert (chunk_pos < table->num_chunks);
 
@@ -803,90 +831,49 @@ mono_jit_info_table_remove (MonoDomain *domain, MonoJitInfo *ji)
 
        /* Debugging code, should be removed. */
        //jit_info_table_check (table);
-
-       mono_jit_info_free_or_queue (domain, ji);
-
-       mono_domain_unlock (domain);
-}
-
-static MonoAotModuleInfoTable*
-mono_aot_module_info_table_new (void)
-{
-       return g_array_new (FALSE, FALSE, sizeof (gpointer));
-}
-
-static int
-aot_info_table_index (MonoAotModuleInfoTable *table, char *addr)
-{
-       int left = 0, right = table->len;
-
-       while (left < right) {
-               int pos = (left + right) / 2;
-               AotModuleInfo *ainfo = g_array_index (table, gpointer, pos);
-               char *start = ainfo->start;
-               char *end = ainfo->end;
-
-               if (addr < start)
-                       right = pos;
-               else if (addr >= end) 
-                       left = pos + 1;
-               else
-                       return pos;
-       }
-
-       return left;
 }
 
 void
-mono_jit_info_add_aot_module (MonoImage *image, gpointer start, gpointer end)
+mono_jit_info_table_remove (MonoDomain *domain, MonoJitInfo *ji)
 {
-       AotModuleInfo *ainfo = g_new0 (AotModuleInfo, 1);
-       int pos;
-
-       ainfo->image = image;
-       ainfo->start = start;
-       ainfo->end = end;
+       MonoJitInfoTable *table;
 
-       mono_appdomains_lock ();
+       mono_domain_lock (domain);
+       table = domain->jit_info_table;
 
-       if (!aot_modules)
-               aot_modules = mono_aot_module_info_table_new ();
+       ++mono_stats.jit_info_table_remove_count;
 
-       pos = aot_info_table_index (aot_modules, start);
+       jit_info_table_remove (table, ji);
 
-       g_array_insert_val (aot_modules, pos, ainfo);
+       mono_jit_info_free_or_queue (domain, ji);
 
-       mono_appdomains_unlock ();
+       mono_domain_unlock (domain);
 }
 
-static MonoImage*
-mono_jit_info_find_aot_module (guint8* addr)
+void
+mono_jit_info_add_aot_module (MonoImage *image, gpointer start, gpointer end)
 {
-       guint left = 0, right;
-
-       if (!aot_modules)
-               return NULL;
+       MonoJitInfo *ji;
 
        mono_appdomains_lock ();
 
-       right = aot_modules->len;
-       while (left < right) {
-               guint pos = (left + right) / 2;
-               AotModuleInfo *ai = g_array_index (aot_modules, gpointer, pos);
-
-               if (addr < (guint8*)ai->start)
-                       right = pos;
-               else if (addr >= (guint8*)ai->end)
-                       left = pos + 1;
-               else {
-                       mono_appdomains_unlock ();
-                       return ai->image;
-               }
+       /*
+        * We reuse MonoJitInfoTable to store AOT module info,
+        * this gives us async-safe lookup.
+        */
+       g_assert (mono_root_domain);
+       if (!mono_root_domain->aot_modules) {
+               mono_root_domain->num_jit_info_tables ++;
+               mono_root_domain->aot_modules = jit_info_table_new (mono_root_domain);
        }
 
-       mono_appdomains_unlock ();
+       ji = g_new0 (MonoJitInfo, 1);
+       ji->d.image = image;
+       ji->code_start = start;
+       ji->code_size = (guint8*)end - (guint8*)start;
+       jit_info_table_add (mono_root_domain, &mono_root_domain->aot_modules, ji);
 
-       return NULL;
+       mono_appdomains_unlock ();
 }
 
 void
@@ -910,7 +897,8 @@ mono_jit_info_get_code_size (MonoJitInfo* ji)
 MonoMethod*
 mono_jit_info_get_method (MonoJitInfo* ji)
 {
-       return ji->method;
+       g_assert (!ji->async);
+       return ji->d.method;
 }
 
 static gpointer
@@ -918,7 +906,7 @@ jit_info_key_extract (gpointer value)
 {
        MonoJitInfo *info = (MonoJitInfo*)value;
 
-       return info->method;
+       return info->d.method;
 }
 
 static gpointer*
@@ -1028,6 +1016,95 @@ mono_jit_info_get_cas_info (MonoJitInfo *ji)
        }
 }
 
+#define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
+#define ALIGN_PTR_TO(ptr,align) (gpointer)((((gssize)(ptr)) + (align - 1)) & (~(align - 1)))
+
+static LockFreeMempool*
+lock_free_mempool_new (void)
+{
+       return g_new0 (LockFreeMempool, 1);
+}
+
+static void
+lock_free_mempool_free (LockFreeMempool *mp)
+{
+       LockFreeMempoolChunk *chunk, *next;
+
+       chunk = mp->chunks;
+       while (chunk) {
+               next = chunk->prev;
+               mono_vfree (chunk, mono_pagesize ());
+               chunk = next;
+       }
+       g_free (mp);
+}
+
+/*
+ * This is async safe
+ */
+static LockFreeMempoolChunk*
+lock_free_mempool_chunk_new (LockFreeMempool *mp, int len)
+{
+       LockFreeMempoolChunk *chunk, *prev;
+       int size;
+
+       size = mono_pagesize ();
+       while (size - sizeof (LockFreeMempoolChunk) < len)
+               size += mono_pagesize ();
+       chunk = mono_valloc (0, size, MONO_MMAP_READ|MONO_MMAP_WRITE);
+       g_assert (chunk);
+       chunk->mem = ALIGN_PTR_TO ((char*)chunk + sizeof (LockFreeMempoolChunk), 16);
+       chunk->size = ((char*)chunk + size) - (char*)chunk->mem;
+       chunk->pos = 0;
+
+       /* Add to list of chunks lock-free */
+       while (TRUE) {
+               prev = mp->chunks;
+               if (InterlockedCompareExchangePointer ((volatile gpointer*)&mp->chunks, chunk, prev) == prev)
+                       break;
+       }
+       chunk->prev = prev;
+
+       return chunk;
+}
+
+/*
+ * This is async safe
+ */
+static gpointer
+lock_free_mempool_alloc0 (LockFreeMempool *mp, guint size)
+{
+       LockFreeMempoolChunk *chunk;
+       gpointer res;
+       int oldpos;
+
+       // FIXME: Free the allocator
+
+       size = ALIGN_TO (size, 8);
+       chunk = mp->current;
+       if (!chunk) {
+               chunk = lock_free_mempool_chunk_new (mp, size);
+               mono_memory_barrier ();
+               /* Publish */
+               mp->current = chunk;
+       }
+
+       /* The code below is lock-free, 'chunk' is shared state */
+       oldpos = InterlockedExchangeAdd (&chunk->pos, size);
+       if (oldpos + size > chunk->size) {
+               chunk = lock_free_mempool_chunk_new (mp, size);
+               g_assert (chunk->pos + size <= chunk->size);
+               res = chunk->mem;
+               chunk->pos += size;
+               mono_memory_barrier ();
+               mp->current = chunk;
+       } else {
+               res = (char*)chunk->mem + oldpos;
+       }
+
+       return res;
+}
+
 void
 mono_install_create_domain_hook (MonoCreateDomainFunc func)
 {
@@ -1200,6 +1277,7 @@ mono_domain_create (void)
 
        domain->mp = mono_mempool_new ();
        domain->code_mp = mono_code_manager_new ();
+       domain->lock_free_mp = lock_free_mempool_new ();
        domain->env = mono_g_hash_table_new_type ((GHashFunc)mono_string_hash, (GCompareFunc)mono_string_equal, MONO_HASH_KEY_VALUE_GC);
        domain->domain_assemblies = NULL;
        domain->assembly_bindings = NULL;
@@ -1213,7 +1291,6 @@ mono_domain_create (void)
        domain->jit_info_table = jit_info_table_new (domain);
        domain->jit_info_free_queue = NULL;
        domain->finalizable_objects_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
-       domain->track_resurrection_handles_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
        domain->ftnptrs_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
 
        InitializeCriticalSection (&domain->lock);
@@ -1227,8 +1304,10 @@ mono_domain_create (void)
        domain_id_alloc (domain);
        mono_appdomains_unlock ();
 
+#ifndef DISABLE_PERFCOUNTERS
        mono_perfcounters->loader_appdomains++;
        mono_perfcounters->loader_total_appdomains++;
+#endif
 
        mono_debug_domain_create (domain);
 
@@ -1274,7 +1353,9 @@ mono_init_internal (const char *filename, const char *exe_filename, const char *
        wapi_init ();
 #endif
 
+#ifndef DISABLE_PERFCOUNTERS
        mono_perfcounters_init ();
+#endif
 
        mono_counters_register ("Max native code in a domain", MONO_COUNTER_INT|MONO_COUNTER_JIT, &max_domain_code_size);
        mono_counters_register ("Max code space allocated in a domain", MONO_COUNTER_INT|MONO_COUNTER_JIT, &max_domain_code_alloc);
@@ -1293,6 +1374,7 @@ mono_init_internal (const char *filename, const char *exe_filename, const char *
        mono_classes_init ();
        mono_loader_init ();
        mono_reflection_init ();
+       mono_runtime_init_tls ();
 
        /* FIXME: When should we release this memory? */
        MONO_GC_REGISTER_ROOT_FIXED (appdomains_list);
@@ -1505,6 +1587,7 @@ mono_init_internal (const char *filename, const char *exe_filename, const char *
                 mono_defaults.corlib, "System", "AppDomain");
        g_assert (mono_defaults.appdomain_class != 0);
 
+#ifndef DISABLE_REMOTING
        mono_defaults.transparent_proxy_class = mono_class_from_name (
                 mono_defaults.corlib, "System.Runtime.Remoting.Proxies", "TransparentProxy");
        g_assert (mono_defaults.transparent_proxy_class != 0);
@@ -1513,6 +1596,15 @@ mono_init_internal (const char *filename, const char *exe_filename, const char *
                 mono_defaults.corlib, "System.Runtime.Remoting.Proxies", "RealProxy");
        g_assert (mono_defaults.real_proxy_class != 0);
 
+       mono_defaults.marshalbyrefobject_class =  mono_class_from_name (
+               mono_defaults.corlib, "System", "MarshalByRefObject");
+       g_assert (mono_defaults.marshalbyrefobject_class != 0);
+
+       mono_defaults.iremotingtypeinfo_class = mono_class_from_name (
+               mono_defaults.corlib, "System.Runtime.Remoting", "IRemotingTypeInfo");
+       g_assert (mono_defaults.iremotingtypeinfo_class != 0);
+#endif
+
        mono_defaults.mono_method_message_class = mono_class_from_name (
                 mono_defaults.corlib, "System.Runtime.Remoting.Messaging", "MonoMethodMessage");
        g_assert (mono_defaults.mono_method_message_class != 0);
@@ -1545,18 +1637,6 @@ mono_init_internal (const char *filename, const char *exe_filename, const char *
                mono_defaults.corlib, "System.Runtime.InteropServices", "Marshal");
        g_assert (mono_defaults.marshal_class != 0);
 
-       mono_defaults.iserializeable_class = mono_class_from_name (
-               mono_defaults.corlib, "System.Runtime.Serialization", "ISerializable");
-       g_assert (mono_defaults.iserializeable_class != 0);
-
-       mono_defaults.serializationinfo_class = mono_class_from_name (
-               mono_defaults.corlib, "System.Runtime.Serialization", "SerializationInfo");
-       g_assert (mono_defaults.serializationinfo_class != 0);
-
-       mono_defaults.streamingcontext_class = mono_class_from_name (
-               mono_defaults.corlib, "System.Runtime.Serialization", "StreamingContext");
-       g_assert (mono_defaults.streamingcontext_class != 0);
-
        mono_defaults.typed_reference_class =  mono_class_from_name (
                mono_defaults.corlib, "System", "TypedReference");
        g_assert (mono_defaults.typed_reference_class != 0);
@@ -1565,18 +1645,10 @@ mono_init_internal (const char *filename, const char *exe_filename, const char *
                mono_defaults.corlib, "System", "RuntimeArgumentHandle");
        g_assert (mono_defaults.argumenthandle_class != 0);
 
-       mono_defaults.marshalbyrefobject_class =  mono_class_from_name (
-               mono_defaults.corlib, "System", "MarshalByRefObject");
-       g_assert (mono_defaults.marshalbyrefobject_class != 0);
-
        mono_defaults.monitor_class =  mono_class_from_name (
                mono_defaults.corlib, "System.Threading", "Monitor");
        g_assert (mono_defaults.monitor_class != 0);
 
-       mono_defaults.iremotingtypeinfo_class = mono_class_from_name (
-               mono_defaults.corlib, "System.Runtime.Remoting", "IRemotingTypeInfo");
-       g_assert (mono_defaults.iremotingtypeinfo_class != 0);
-
        mono_defaults.runtimesecurityframe_class = mono_class_from_name (
                mono_defaults.corlib, "System.Security", "RuntimeSecurityFrame");
 
@@ -1608,21 +1680,14 @@ mono_init_internal (const char *filename, const char *exe_filename, const char *
                mono_defaults.corlib, "System.Reflection", "CustomAttributeData");
 
        /* these are initialized lazily when COM features are used */
-       mono_defaults.variant_class = NULL;
-       mono_defaults.com_object_class = NULL;
-       mono_defaults.com_interop_proxy_class = NULL;
-       mono_defaults.iunknown_class = NULL;
-       mono_defaults.idispatch_class = NULL;
 
-       /*
-        * Note that mono_defaults.generic_*_class is only non-NULL if we're
-        * using the 2.0 corlib.
-        */
        mono_class_init (mono_defaults.array_class);
        mono_defaults.generic_nullable_class = mono_class_from_name (
                mono_defaults.corlib, "System", "Nullable`1");
        mono_defaults.generic_ilist_class = mono_class_from_name (
                mono_defaults.corlib, "System.Collections.Generic", "IList`1");
+       mono_defaults.generic_ireadonlylist_class = mono_class_from_name (
+               mono_defaults.corlib, "System.Collections.Generic", "IReadOnlyList`1");
 
        domain->friendly_name = g_path_get_basename (filename);
 
@@ -1688,46 +1753,6 @@ mono_init_version (const char *domain_name, const char *version)
        return mono_init_internal (domain_name, NULL, version);
 }
 
-/**
- * mono_init_com_types:
- *
- * Initializes all types needed for COM Interop in mono_defaults structure. 
- */
-void 
-mono_init_com_types (void)
-{
-       static gboolean initialized = FALSE;
-
-       if (initialized)
-               return;
-       
-       /* FIXME: do I need some threading protection here */
-
-       g_assert (mono_defaults.corlib);
-
-       mono_defaults.variant_class = mono_class_from_name (
-               mono_defaults.corlib, "System", "Variant");
-       g_assert (mono_defaults.variant_class != 0);
-
-       mono_defaults.com_object_class = mono_class_from_name (
-               mono_defaults.corlib, "System", "__ComObject");
-       g_assert (mono_defaults.com_object_class != 0);
-
-       mono_defaults.com_interop_proxy_class = mono_class_from_name (
-               mono_defaults.corlib, "Mono.Interop", "ComInteropProxy");
-       g_assert (mono_defaults.com_interop_proxy_class != 0);
-
-       mono_defaults.iunknown_class = mono_class_from_name (
-               mono_defaults.corlib, "Mono.Interop", "IUnknown");
-       g_assert (mono_defaults.iunknown_class != 0);
-
-       mono_defaults.idispatch_class = mono_class_from_name (
-               mono_defaults.corlib, "Mono.Interop", "IDispatch");
-       g_assert (mono_defaults.idispatch_class != 0);
-
-       initialized = TRUE;
-}
-
 /**
  * mono_cleanup:
  *
@@ -1893,12 +1918,6 @@ mono_domain_assembly_open (MonoDomain *domain, const char *name)
        return ass;
 }
 
-static void
-free_slist (gpointer key, gpointer value, gpointer user_data)
-{
-       g_slist_free (value);
-}
-
 static void
 unregister_vtable_reflection_type (MonoVTable *vtable)
 {
@@ -1913,6 +1932,8 @@ mono_domain_free (MonoDomain *domain, gboolean force)
 {
        int code_size, code_alloc;
        GSList *tmp;
+       gpointer *p;
+
        if ((domain == mono_root_domain) && !force) {
                g_warning ("cant unload root domain");
                return;
@@ -1956,6 +1977,13 @@ mono_domain_free (MonoDomain *domain, gboolean force)
 
        mono_reflection_cleanup_domain (domain);
 
+       /* This must be done before type_hash is freed */
+       if (domain->class_vtable_array) {
+               int i;
+               for (i = 0; i < domain->class_vtable_array->len; ++i)
+                       unregister_vtable_reflection_type (g_ptr_array_index (domain->class_vtable_array, i));
+       }
+
        if (domain->type_hash) {
                mono_g_hash_table_destroy (domain->type_hash);
                domain->type_hash = NULL;
@@ -1965,22 +1993,34 @@ mono_domain_free (MonoDomain *domain, gboolean force)
                domain->type_init_exception_hash = NULL;
        }
 
-       if (domain->class_vtable_array) {
-               int i;
-               for (i = 0; i < domain->class_vtable_array->len; ++i)
-                       unregister_vtable_reflection_type (g_ptr_array_index (domain->class_vtable_array, i));
-       }
-
        for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
                MonoAssembly *ass = tmp->data;
                mono_assembly_release_gc_roots (ass);
        }
 
+       /* Have to zero out reference fields since they will be invalidated by the clear_domain () call below */
+       for (p = (gpointer*)&domain->MONO_DOMAIN_FIRST_OBJECT; p < (gpointer*)&domain->MONO_DOMAIN_FIRST_GC_TRACKED; ++p)
+               *p = NULL;
+
        /* This needs to be done before closing assemblies */
        mono_gc_clear_domain (domain);
 
+       /* Close dynamic assemblies first, since they have no ref count */
        for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
                MonoAssembly *ass = tmp->data;
+               if (!ass->image || !ass->image->dynamic)
+                       continue;
+               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);
+               if (!mono_assembly_close_except_image_pools (ass))
+                       tmp->data = NULL;
+       }
+
+       for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
+               MonoAssembly *ass = tmp->data;
+               if (!ass)
+                       continue;
+               if (!ass->image || ass->image->dynamic)
+                       continue;
                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);
                if (!mono_assembly_close_except_image_pools (ass))
                        tmp->data = NULL;
@@ -2035,6 +2075,8 @@ mono_domain_free (MonoDomain *domain, gboolean force)
         * this will free them.
         */
        mono_thread_hazardous_try_free_all ();
+       if (domain->aot_modules)
+               jit_info_table_free (domain->aot_modules);
        g_assert (domain->num_jit_info_tables == 1);
        jit_info_table_free (domain->jit_info_table);
        domain->jit_info_table = NULL;
@@ -2050,21 +2092,19 @@ mono_domain_free (MonoDomain *domain, gboolean force)
        mono_mempool_invalidate (domain->mp);
        mono_code_manager_invalidate (domain->code_mp);
 #else
+#ifndef DISABLE_PERFCOUNTERS
        mono_perfcounters->loader_bytes -= mono_mempool_get_allocated (domain->mp);
+#endif
        mono_mempool_destroy (domain->mp);
        domain->mp = NULL;
        mono_code_manager_destroy (domain->code_mp);
        domain->code_mp = NULL;
 #endif 
+       lock_free_mempool_free (domain->lock_free_mp);
+       domain->lock_free_mp = NULL;
 
        g_hash_table_destroy (domain->finalizable_objects_hash);
        domain->finalizable_objects_hash = NULL;
-       if (domain->track_resurrection_objects_hash) {
-               g_hash_table_foreach (domain->track_resurrection_objects_hash, free_slist, NULL);
-               g_hash_table_destroy (domain->track_resurrection_objects_hash);
-       }
-       if (domain->track_resurrection_handles_hash)
-               g_hash_table_destroy (domain->track_resurrection_handles_hash);
        if (domain->method_rgctx_hash) {
                g_hash_table_destroy (domain->method_rgctx_hash);
                domain->method_rgctx_hash = NULL;
@@ -2094,7 +2134,9 @@ mono_domain_free (MonoDomain *domain, gboolean force)
 
        mono_gc_free_fixed (domain);
 
+#ifndef DISABLE_PERFCOUNTERS
        mono_perfcounters->loader_appdomains--;
+#endif
 
        if (domain == mono_root_domain)
                mono_root_domain = NULL;
@@ -2138,7 +2180,9 @@ mono_domain_alloc (MonoDomain *domain, guint size)
        gpointer res;
 
        mono_domain_lock (domain);
+#ifndef DISABLE_PERFCOUNTERS
        mono_perfcounters->loader_bytes += size;
+#endif
        res = mono_mempool_alloc (domain->mp, size);
        mono_domain_unlock (domain);
 
@@ -2156,13 +2200,21 @@ mono_domain_alloc0 (MonoDomain *domain, guint size)
        gpointer res;
 
        mono_domain_lock (domain);
+#ifndef DISABLE_PERFCOUNTERS
        mono_perfcounters->loader_bytes += size;
+#endif
        res = mono_mempool_alloc0 (domain->mp, size);
        mono_domain_unlock (domain);
 
        return res;
 }
 
+gpointer
+mono_domain_alloc0_lock_free (MonoDomain *domain, guint size)
+{
+       return lock_free_mempool_alloc0 (domain->lock_free_mp, size);
+}
+
 /*
  * mono_domain_code_reserve:
  *
@@ -2306,7 +2358,7 @@ mono_domain_add_class_static_data (MonoDomain *domain, MonoClass *klass, gpointe
                if (next >= size) {
                        /* 'data' is allocated by alloc_fixed */
                        gpointer *new_array = mono_gc_alloc_fixed (sizeof (gpointer) * (size * 2), MONO_GC_ROOT_DESCR_FOR_FIXED (size * 2));
-                       mono_gc_memmove (new_array, domain->static_data_array, sizeof (gpointer) * size);
+                       mono_gc_memmove_aligned (new_array, domain->static_data_array, sizeof (gpointer) * size);
                        size *= 2;
                        new_array [1] = GINT_TO_POINTER (size);
                        mono_gc_free_fixed (domain->static_data_array);
@@ -2703,4 +2755,3 @@ mono_framework_version (void)
 {
        return current_runtime->framework_version [0] - '0';
 }
-