Fix some AOT memory leaks.
[mono.git] / mono / mini / mini.c
index 0333554a3ca0f57712b5c1bbcc824a94b02d2bbe..fcb2ca1109df19729f605f5da8eff44f6ca8d844 100644 (file)
@@ -1,13 +1,15 @@
 /*
  * mini.c: The new Mono code generator.
  *
- * Author:
+ * Authors:
  *   Paolo Molaro (lupus@ximian.com)
  *   Dietmar Maurer (dietmar@ximian.com)
  *
- * (C) 2002 Ximian, Inc.
+ * Copyright 2002-2003 Ximian, Inc.
+ * Coprygith 2003-2010 Novell, Inc.
  */
 
+#define MONO_LLVM_IN_MINI 1
 #include <config.h>
 #include <signal.h>
 #ifdef HAVE_ALLOCA_H
@@ -45,6 +47,7 @@
 #include <mono/metadata/verify-internals.h>
 #include <mono/metadata/mempool-internals.h>
 #include <mono/metadata/attach.h>
+#include <mono/metadata/runtime.h>
 #include <mono/utils/mono-math.h>
 #include <mono/utils/mono-compiler.h>
 #include <mono/utils/mono-counters.h>
@@ -53,6 +56,7 @@
 #include <mono/utils/dtrace.h>
 
 #include "mini.h"
+#include "mini-llvm.h"
 #include "tasklets.h"
 #include <string.h>
 #include <ctype.h>
@@ -72,10 +76,16 @@ static gpointer mono_jit_compile_method_with_opt (MonoMethod *method, guint32 op
 MonoMethodSignature *helper_sig_class_init_trampoline = NULL;
 MonoMethodSignature *helper_sig_domain_get = NULL;
 MonoMethodSignature *helper_sig_generic_class_init_trampoline = NULL;
+MonoMethodSignature *helper_sig_generic_class_init_trampoline_llvm = NULL;
 MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline = NULL;
 MonoMethodSignature *helper_sig_monitor_enter_exit_trampoline = NULL;
 MonoMethodSignature *helper_sig_monitor_enter_exit_trampoline_llvm = NULL;
 
+#ifdef __native_client_codegen__
+/* Default alignment for Native Client is 32-byte. */
+guint8 nacl_align_byte = 0xe0;
+#endif
+
 static guint32 default_opt = 0;
 static gboolean default_opt_set = FALSE;
 
@@ -106,25 +116,11 @@ gboolean mono_do_signal_chaining;
 static gboolean        mono_using_xdebug;
 static int mini_verbose = 0;
 
-/* Statistics */
-#ifdef ENABLE_LLVM
-static int methods_with_llvm, methods_without_llvm;
-#endif
-
 /*
- * This flag controls whenever the runtime uses LLVM compiled code.
- * Enabling this causes different/slower code paths to be used, which is why it
- * defaults to FALSE.
- * Changes when this flag is set include:
- * - a per method vtable trampoline is used to handle virtual calls, instead of only
- *   one trampoline.
- * - fast generic virtual calls are not supported.
+ * This flag controls whenever the runtime uses LLVM for JIT compilation, and whenever
+ * it can load AOT code compiled by LLVM.
  */
-#ifdef ENABLE_LLVM
-gboolean mono_use_llvm = TRUE;
-#else
 gboolean mono_use_llvm = FALSE;
-#endif
 
 #define mono_jit_lock() EnterCriticalSection (&jit_mutex)
 #define mono_jit_unlock() LeaveCriticalSection (&jit_mutex)
@@ -156,6 +152,82 @@ gboolean disable_vtypes_in_regs = FALSE;
 
 gboolean mono_dont_free_global_codeman;
 
+#ifdef __native_client_codegen__
+
+/* Prevent instructions from straddling a 32-byte alignment boundary.   */
+/* Instructions longer than 32 bytes must be aligned internally.        */
+/* IN: pcode, instlen                                                   */
+/* OUT: pcode                                                           */
+void mono_nacl_align_inst(guint8 **pcode, int instlen) {
+  int space_in_block;
+
+  space_in_block = kNaClAlignment - ((uintptr_t)(*pcode) & kNaClAlignmentMask);
+
+  if (G_UNLIKELY (instlen >= kNaClAlignment)) {
+    g_assert_not_reached();
+  } else if (instlen > space_in_block) {
+    *pcode = mono_arch_nacl_pad(*pcode, space_in_block);
+  }
+}
+
+/* Move emitted call sequence to the end of a kNaClAlignment-byte block.  */
+/* IN: start    pointer to start of call sequence                         */
+/* IN: pcode    pointer to end of call sequence (current "IP")            */
+/* OUT: start   pointer to the start of the call sequence after padding   */
+/* OUT: pcode   pointer to the end of the call sequence after padding     */
+void mono_nacl_align_call(guint8 **start, guint8 **pcode) {
+  const size_t MAX_NACL_CALL_LENGTH = kNaClAlignment;
+  guint8 copy_of_call[MAX_NACL_CALL_LENGTH];
+  guint8 *temp;
+
+  const size_t length = (size_t)((*pcode)-(*start));
+  g_assert(length < MAX_NACL_CALL_LENGTH);
+
+  memcpy(copy_of_call, *start, length);
+  temp = mono_nacl_pad_call(*start, (guint8)length);
+  memcpy(temp, copy_of_call, length);
+  (*start) = temp;
+  (*pcode) = temp + length;
+}
+
+/* mono_nacl_pad_call(): Insert padding for Native Client call instructions */
+/*    code     pointer to buffer for emitting code                          */
+/*    ilength  length of call instruction                                   */
+guint8 *mono_nacl_pad_call(guint8 *code, guint8 ilength) {
+  int freeSpaceInBlock = kNaClAlignment - ((uintptr_t)code & kNaClAlignmentMask);
+  int padding = freeSpaceInBlock - ilength;
+
+  if (padding < 0) {
+    /* There isn't enough space in this block for the instruction. */
+    /* Fill this block and start a new one.                        */
+    code = mono_arch_nacl_pad(code, freeSpaceInBlock);
+    freeSpaceInBlock = kNaClAlignment;
+    padding = freeSpaceInBlock - ilength;
+  }
+  g_assert(ilength > 0);
+  g_assert(padding >= 0);
+  g_assert(padding < kNaClAlignment);
+  if (0 == padding) return code;
+  return mono_arch_nacl_pad(code, padding);
+}
+
+guint8 *mono_nacl_align(guint8 *code) {
+  int padding = kNaClAlignment - ((uintptr_t)code & kNaClAlignmentMask);
+  if (padding != kNaClAlignment) code = mono_arch_nacl_pad(code, padding);
+  return code;
+}
+
+void mono_nacl_fix_patches(const guint8 *code, MonoJumpInfo *ji)
+{
+  MonoJumpInfo *patch_info;
+  for (patch_info = ji; patch_info; patch_info = patch_info->next) {
+    unsigned char *ip = patch_info->ip.i + code;
+    ip = mono_arch_nacl_skip_nops(ip);
+    patch_info->ip.i = ip - code;
+  }
+}
+#endif  /* __native_client_codegen__ */
+
 gboolean
 mono_running_on_valgrind (void)
 {
@@ -425,9 +497,15 @@ mono_tramp_info_create (const char *name, guint8 *code, guint32 code_size, MonoJ
 void
 mono_tramp_info_free (MonoTrampInfo *info)
 {
+       GSList *l;
+
        g_free (info->name);
 
-       // FIXME: ji + unwind_ops
+       // FIXME: ji
+       for (l = info->unwind_ops; l; l = l->next)
+               g_free (l->data);
+       g_slist_free (info->unwind_ops);
+       g_free (info);
 }
 
 #define MONO_INIT_VARINFO(vi,id) do { \
@@ -1343,6 +1421,7 @@ create_helper_signature (void)
        helper_sig_domain_get = mono_create_icall_signature ("ptr");
        helper_sig_class_init_trampoline = mono_create_icall_signature ("void");
        helper_sig_generic_class_init_trampoline = mono_create_icall_signature ("void");
+       helper_sig_generic_class_init_trampoline_llvm = mono_create_icall_signature ("void ptr");
        helper_sig_rgctx_lazy_fetch_trampoline = mono_create_icall_signature ("ptr ptr");
        helper_sig_monitor_enter_exit_trampoline = mono_create_icall_signature ("void");
        helper_sig_monitor_enter_exit_trampoline_llvm = mono_create_icall_signature ("void object");
@@ -1560,12 +1639,11 @@ mono_allocate_stack_slots_full2 (MonoCompile *cfg, gboolean backward, guint32 *s
 #else
                case MONO_TYPE_I8:
 #endif
-#ifdef HAVE_SGEN_GC
-                       slot_info = &scalar_stack_slots [MONO_TYPE_I];
-                       break;
-#else
+                       if (cfg->disable_ref_noref_stack_slot_share) {
+                               slot_info = &scalar_stack_slots [MONO_TYPE_I];
+                               break;
+                       }
                        /* Fall through */
-#endif
 
                case MONO_TYPE_CLASS:
                case MONO_TYPE_OBJECT:
@@ -1850,12 +1928,11 @@ mono_allocate_stack_slots_full (MonoCompile *cfg, gboolean backward, guint32 *st
 #else
                        case MONO_TYPE_I8:
 #endif
-#ifdef HAVE_SGEN_GC
-                               slot_info = &scalar_stack_slots [MONO_TYPE_I];
-                               break;
-#else
+                               if (cfg->disable_ref_noref_stack_slot_share) {
+                                       slot_info = &scalar_stack_slots [MONO_TYPE_I];
+                                       break;
+                               }
                                /* Fall through */
-#endif
 
                        case MONO_TYPE_CLASS:
                        case MONO_TYPE_OBJECT:
@@ -2201,6 +2278,8 @@ mono_verify_cfg (MonoCompile *cfg)
 void
 mono_destroy_compile (MonoCompile *cfg)
 {
+       GSList *l;
+
        if (cfg->header)
                mono_metadata_free_mh (cfg->header);
        //mono_mempool_stats (cfg->mempool);
@@ -2211,11 +2290,13 @@ mono_destroy_compile (MonoCompile *cfg)
                g_hash_table_destroy (cfg->spvars);
        if (cfg->exvars)
                g_hash_table_destroy (cfg->exvars);
-       mono_mempool_destroy (cfg->mempool);
+       for (l = cfg->headers_to_free; l; l = l->next)
+               mono_metadata_free_mh (l->data);
        g_list_free (cfg->ldstr_list);
        g_hash_table_destroy (cfg->token_info_hash);
        if (cfg->abs_patches)
                g_hash_table_destroy (cfg->abs_patches);
+       mono_mempool_destroy (cfg->mempool);
 
        g_free (cfg->varinfo);
        g_free (cfg->vars);
@@ -3326,7 +3407,17 @@ mono_codegen (MonoCompile *cfg)
        }
 
        memcpy (code, cfg->native_code, cfg->code_len);
+#ifdef __native_client_codegen__
+       if (cfg->native_code_alloc) {
+               g_free (cfg->native_code_alloc);
+               cfg->native_code_alloc = 0;
+       }
+       else if (cfg->native_code) {
+               g_free (cfg->native_code);
+       }
+#else
        g_free (cfg->native_code);
+#endif
        cfg->native_code = code;
        code = cfg->native_code + cfg->code_len;
   
@@ -3365,6 +3456,10 @@ if (valgrind_register){
        mono_arch_save_unwind_info (cfg);
 #endif
        
+#ifdef __native_client_codegen__
+       mono_nacl_fix_patches (cfg->native_code, cfg->patch_info);
+#endif
+
        mono_arch_patch_code (cfg->method, cfg->domain, cfg->native_code, cfg->patch_info, cfg->run_cctors);
 
        if (cfg->method->dynamic) {
@@ -3478,12 +3573,18 @@ create_jit_info (MonoCompile *cfg, MonoMethod *method_to_compile)
                                mini_method_get_context (method_to_compile)->method_inst ||
                                method_to_compile->klass->valuetype) {
                        inst = cfg->rgctx_var;
-                       g_assert (inst->opcode == OP_REGOFFSET);
+                       if (!COMPILE_LLVM (cfg))
+                               g_assert (inst->opcode == OP_REGOFFSET);
                } else {
                        inst = cfg->args [0];
                }
 
-               if (inst->opcode == OP_REGVAR) {
+               if (COMPILE_LLVM (cfg)) {
+                       g_assert (cfg->llvm_this_reg != -1);
+                       gi->this_in_reg = 0;
+                       gi->this_reg = cfg->llvm_this_reg;
+                       gi->this_offset = cfg->llvm_this_offset;
+               } else if (inst->opcode == OP_REGVAR) {
                        gi->this_in_reg = 1;
                        gi->this_reg = inst->dreg;
                } else {
@@ -3595,18 +3696,18 @@ create_jit_info (MonoCompile *cfg, MonoMethod *method_to_compile)
                                ei->data.handler_end = cfg->native_code + end_offset;
                        }
                }
+       }
 
-               if (G_UNLIKELY (cfg->verbose_level >= 4)) {
-                       for (i = 0; i < jinfo->num_clauses; i++) {
-                               MonoJitExceptionInfo *ei = &jinfo->clauses [i];
-                               int start = (guint8*)ei->try_start - cfg->native_code;
-                               int end = (guint8*)ei->try_end - cfg->native_code;
-                               int handler = (guint8*)ei->handler_start - cfg->native_code;
+       if (G_UNLIKELY (cfg->verbose_level >= 4)) {
+               int i;
+               for (i = 0; i < jinfo->num_clauses; i++) {
+                       MonoJitExceptionInfo *ei = &jinfo->clauses [i];
+                       int start = (guint8*)ei->try_start - cfg->native_code;
+                       int end = (guint8*)ei->try_end - cfg->native_code;
+                       int handler = (guint8*)ei->handler_start - cfg->native_code;
 
-                               printf ("JitInfo EH clause %d flags %x try %x-%x handler %x\n", i, ei->flags, start, end, handler);
-                       }
+                       printf ("JitInfo EH clause %d flags %x try %x-%x handler %x\n", i, ei->flags, start, end, handler);
                }
-
        }
 
        /* 
@@ -3724,7 +3825,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        MonoCompile *cfg;
        int dfn, i, code_size_ratio;
        gboolean deadce_has_run = FALSE;
-       gboolean try_generic_shared, try_llvm;
+       gboolean try_generic_shared, try_llvm = FALSE;
        MonoMethod *method_to_compile, *method_to_register;
 
        mono_jit_stats.methods_compiled++;
@@ -3752,10 +3853,8 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
                        mono_stats.generics_unsharable_methods++;
        }
 
-       try_llvm = TRUE;
-
-#ifndef ENABLE_LLVM
-       try_llvm = FALSE;
+#ifdef ENABLE_LLVM
+       try_llvm = mono_use_llvm;
 #endif
 
  restart_compile:
@@ -3801,25 +3900,6 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        }
        cfg->method_to_register = method_to_register;
 
-       if (cfg->compile_llvm) {
-               /* No way to obtain the location info for 'this' */
-               if (try_generic_shared) {
-                       cfg->exception_message = g_strdup ("gshared");
-                       cfg->disable_llvm = TRUE;
-               }
-
-               if (cfg->method->save_lmf) {
-                       cfg->exception_message = g_strdup ("lmf");
-                       cfg->disable_llvm = TRUE;
-               }
-
-               /* FIXME: */
-               if (cfg->method->dynamic) {
-                       cfg->exception_message = g_strdup ("dynamic.");
-                       cfg->disable_llvm = TRUE;
-               }
-       }
-
        mono_error_init (&err);
        sig = mono_method_signature_checked (cfg->method, &err);        
        if (!sig) {
@@ -3846,39 +3926,30 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
                return cfg;
        }
 
-       if (header->clauses) {
-               /*
-                * FIXME: LLLVM 2.6/SVN no longer seems to generate correct exception info
-                * for JITted code.
-                */
-               cfg->exception_message = g_strdup ("clauses");
-               cfg->disable_llvm = TRUE;
-       }
-
 #ifdef ENABLE_LLVM
        {
                static gboolean inited;
 
                if (!inited) {
-                       mono_counters_register ("Methods JITted using LLVM", MONO_COUNTER_JIT | MONO_COUNTER_INT, &methods_with_llvm);  
-                       mono_counters_register ("Methods JITted using mono JIT", MONO_COUNTER_JIT | MONO_COUNTER_INT, &methods_without_llvm);
                        inited = TRUE;
                }
-       
+
                /* 
                 * Check for methods which cannot be compiled by LLVM early, to avoid
                 * the extra compilation pass.
                 */
-               if (COMPILE_LLVM (cfg) && cfg->disable_llvm) {
-                       if (cfg->verbose_level >= 1) {
-                               //nm = mono_method_full_name (cfg->method, TRUE);
-                               printf ("LLVM failed for '%s': %s\n", method->name, cfg->exception_message);
-                               //g_free (nm);
+               if (COMPILE_LLVM (cfg)) {
+                       mono_llvm_check_method_supported (cfg);
+                       if (cfg->disable_llvm) {
+                               if (cfg->verbose_level >= 1) {
+                                       //nm = mono_method_full_name (cfg->method, TRUE);
+                                       printf ("LLVM failed for '%s': %s\n", method->name, cfg->exception_message);
+                                       //g_free (nm);
+                               }
+                               mono_destroy_compile (cfg);
+                               try_llvm = FALSE;
+                               goto restart_compile;
                        }
-                       InterlockedIncrement (&methods_without_llvm);
-                       mono_destroy_compile (cfg);
-                       try_llvm = FALSE;
-                       goto restart_compile;
                }
        }
 #endif
@@ -3929,7 +4000,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
                cfg->compute_precise_live_ranges = TRUE;
        }
 
-       mini_gc_init_gc_map (cfg);
+       mini_gc_init_cfg (cfg);
 
        if (COMPILE_LLVM (cfg)) {
                cfg->opt |= MONO_OPT_ABCREM;
@@ -4276,7 +4347,8 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
 #endif
 
        if (cfg->comp_done & MONO_COMP_SSA && COMPILE_LLVM (cfg)) {
-               if ((cfg->flags & (MONO_CFG_HAS_LDELEMA|MONO_CFG_HAS_CHECK_THIS)) && (cfg->opt & MONO_OPT_ABCREM))
+               /* This removes MONO_INST_FAULT flags too so perform it unconditionally */
+               if (cfg->opt & MONO_OPT_ABCREM)
                        mono_perform_abc_removal (cfg);
        }
 
@@ -4449,14 +4521,11 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
                                printf ("LLVM failed for '%s': %s\n", method->name, cfg->exception_message);
                                //g_free (nm);
                        }
-                       InterlockedIncrement (&methods_without_llvm);
                        mono_destroy_compile (cfg);
                        try_llvm = FALSE;
                        goto restart_compile;
                }
 
-               InterlockedIncrement (&methods_with_llvm);
-
                if (cfg->verbose_level > 0 && !cfg->compile_aot) {
                        nm = mono_method_full_name (cfg->method, TRUE);
                        g_print ("LLVM Method %s emitted at %p to %p (code length %d) [%s]\n", 
@@ -4469,6 +4538,11 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
                mono_codegen (cfg);
        }
 
+       if (COMPILE_LLVM (cfg))
+               InterlockedIncrement (&mono_jit_stats.methods_with_llvm);
+       else
+               InterlockedIncrement (&mono_jit_stats.methods_without_llvm);
+
        if (cfg->verbose_level >= 2) {
                char *id =  mono_method_full_name (cfg->method, FALSE);
                mono_disassemble_code (cfg, cfg->native_code, cfg->code_len, id + 3);
@@ -4672,6 +4746,7 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
                //mono_debug_add_wrapper (method, nm);
        } else if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
                const char *name = method->name;
+               char *full_name, *msg;
                MonoMethod *nm;
 
                if (method->klass->parent == mono_defaults.multicastdelegate_class) {
@@ -4704,6 +4779,12 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
                                return mono_get_addr_from_ftnptr (mono_compile_method (nm));
                        }
                }
+
+               full_name = mono_method_full_name (method, TRUE);
+               msg = g_strdup_printf ("Unrecognizable runtime implemented method '%s'", full_name);
+               *jit_ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "InvalidProgramException", msg);
+               g_free (full_name);
+               g_free (msg);
                return NULL;
        }
 
@@ -4857,10 +4938,10 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
 
        vtable = mono_class_vtable (target_domain, method->klass);
        if (!vtable) {
-               MonoException *exc;
-               exc = mono_class_get_exception_for_failure (method->klass);
-               g_assert (exc);
-               mono_raise_exception (exc);
+               ex = mono_class_get_exception_for_failure (method->klass);
+               g_assert (ex);
+               *jit_ex = ex;
+               return NULL;
        }
 
        if (prof_options & MONO_PROFILE_JIT_COMPILATION) {
@@ -5239,6 +5320,10 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec
                mono_runtime_class_init (info->vtable);
        }
 
+       /* The wrappers expect this to be initialized to NULL */
+       if (exc)
+               *exc = NULL;
+
 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
        if (info->dyn_call_info) {
                MonoMethodSignature *sig = mono_method_signature (method);
@@ -5446,25 +5531,45 @@ mono_jit_create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, Mon
        return mono_get_addr_from_ftnptr (addr);
 }
 
-#ifdef MONO_ARCH_HAVE_IMT
-static G_GNUC_UNUSED gpointer
-mini_get_imt_trampoline (void)
-{
-       static gpointer tramp = NULL;
-       if (!tramp)
-               tramp = mono_create_specific_trampoline (MONO_FAKE_IMT_METHOD, MONO_TRAMPOLINE_JIT, mono_get_root_domain (), NULL);
-       return tramp;
-}
-#endif
+static gpointer *vtable_trampolines;
+static int vtable_trampolines_size;
 
 gpointer
 mini_get_vtable_trampoline (int slot_index)
 {
-       static gpointer tramp = NULL;
+       int index = slot_index + MONO_IMT_SIZE;
 
-       if (!tramp)
-               tramp = mono_create_specific_trampoline (MONO_FAKE_VTABLE_METHOD, MONO_TRAMPOLINE_JIT, mono_get_root_domain (), NULL);
-       return tramp;
+       g_assert (slot_index >= - MONO_IMT_SIZE);
+       if (!vtable_trampolines || slot_index + MONO_IMT_SIZE >= vtable_trampolines_size) {
+               mono_jit_lock ();
+               if (!vtable_trampolines || index >= vtable_trampolines_size) {
+                       int new_size;
+                       gpointer new_table;
+
+                       new_size = vtable_trampolines_size ? vtable_trampolines_size * 2 : 128;
+                       while (new_size <= index)
+                               new_size *= 2;
+                       new_table = g_new0 (gpointer, new_size);
+
+                       if (vtable_trampolines)
+                               memcpy (new_table, vtable_trampolines, vtable_trampolines_size * sizeof (gpointer));
+                       g_free (vtable_trampolines);
+                       mono_memory_barrier ();
+                       vtable_trampolines = new_table;
+                       vtable_trampolines_size = new_size;
+               }
+               mono_jit_unlock ();
+       }
+
+       if (!vtable_trampolines [index])
+               vtable_trampolines [index] = mono_create_specific_trampoline (GUINT_TO_POINTER (slot_index), MONO_TRAMPOLINE_VCALL, mono_get_root_domain (), NULL);
+       return vtable_trampolines [index];
+}
+
+static gpointer
+mini_get_imt_trampoline (int slot_index)
+{
+       return mini_get_vtable_trampoline (slot_index - MONO_IMT_SIZE);
 }
 
 static void
@@ -5485,6 +5590,8 @@ mini_parse_debug_options (void)
                        debug_options.handle_sigint = TRUE;
                else if (!strcmp (arg, "keep-delegates"))
                        debug_options.keep_delegates = TRUE;
+               else if (!strcmp (arg, "reverse-pinvoke-exceptions"))
+                       debug_options.reverse_pinvoke_exceptions = TRUE;
                else if (!strcmp (arg, "collect-pagefault-stats"))
                        debug_options.collect_pagefault_stats = TRUE;
                else if (!strcmp (arg, "break-on-unverified"))
@@ -5505,9 +5612,11 @@ mini_parse_debug_options (void)
                        debug_options.gen_seq_points = TRUE;
                else if (!strcmp (arg, "init-stacks"))
                        debug_options.init_stacks = TRUE;
+               else if (!strcmp (arg, "casts"))
+                       debug_options.better_cast_details = TRUE;
                else {
                        fprintf (stderr, "Invalid option for the MONO_DEBUG env variable: %s\n", arg);
-                       fprintf (stderr, "Available options: 'handle-sigint', 'keep-delegates', 'collect-pagefault-stats', 'break-on-unverified', 'no-gdb-backtrace', 'dont-free-domains', 'suspend-on-sigsegv', 'dyn-runtime-invoke', 'gdb', 'explicit-null-checks', 'init-stacks'\n");
+                       fprintf (stderr, "Available options: 'handle-sigint', 'keep-delegates', 'reverse-pinvoke-exceptions', 'collect-pagefault-stats', 'break-on-unverified', 'no-gdb-backtrace', 'dont-free-domains', 'suspend-on-sigsegv', 'dyn-runtime-invoke', 'gdb', 'explicit-null-checks', 'init-stacks'\n");
                        exit (1);
                }
        }
@@ -5558,6 +5667,15 @@ mini_get_addr_from_ftnptr (gpointer descr)
 #endif
 }      
 
+static void
+register_jit_stats (void)
+{
+       mono_counters_register ("Compiled methods", MONO_COUNTER_JIT | MONO_COUNTER_LONG, &mono_jit_stats.methods_compiled);
+       mono_counters_register ("Methods from AOT", MONO_COUNTER_JIT | MONO_COUNTER_LONG, &mono_jit_stats.methods_aot);
+       mono_counters_register ("Methods JITted using LLVM", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_with_llvm);   
+       mono_counters_register ("Methods JITted using mono JIT", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_without_llvm);
+}
+
 static void runtime_invoke_info_free (gpointer value);
  
 static void
@@ -5648,7 +5766,7 @@ mini_init (const char *filename, const char *runtime_version)
 
        MONO_PROBE_VES_INIT_BEGIN ();
 
-#ifdef __linux__
+#if defined(__linux__) && !defined(__native_client__)
        if (access ("/proc/self/maps", F_OK) != 0) {
                g_print ("Mono requires /proc to be mounted.\n");
                exit (1);
@@ -5683,10 +5801,8 @@ mini_init (const char *filename, const char *runtime_version)
 
 #ifdef MONO_ARCH_HAVE_IMT
        if (mono_use_imt) {
-               if (!mono_use_llvm) {
-                       /* LLVM needs a per-method vtable trampoline */
-                       callbacks.get_vtable_trampoline = mini_get_vtable_trampoline;
-               }
+               callbacks.get_vtable_trampoline = mini_get_vtable_trampoline;
+               callbacks.get_imt_trampoline = mini_get_imt_trampoline;
        }
 #endif
 
@@ -5716,7 +5832,12 @@ mini_init (const char *filename, const char *runtime_version)
        }
 
 #ifdef ENABLE_LLVM
-       mono_llvm_init ();
+       if (!mono_llvm_load (NULL)) {
+               mono_use_llvm = FALSE;
+               fprintf (stderr, "Mono Warning: llvm support could not be loaded.\n");
+       }
+       if (mono_use_llvm)
+               mono_llvm_init ();
 #endif
 
        mono_trampolines_init ();
@@ -5755,15 +5876,7 @@ mini_init (const char *filename, const char *runtime_version)
 #ifdef JIT_TRAMPOLINES_WORK
        mono_install_compile_method (mono_jit_compile_method);
        mono_install_free_method (mono_jit_free_method);
-#ifdef MONO_ARCH_LLVM_SUPPORTED
-       if (mono_use_llvm)
-               /* The runtime currently only uses this for filling out vtables */
-               mono_install_trampoline (mono_create_llvm_vcall_trampoline);
-       else
-               mono_install_trampoline (mono_create_jit_trampoline);
-#else
        mono_install_trampoline (mono_create_jit_trampoline);
-#endif
        mono_install_jump_trampoline (mono_create_jump_trampoline);
        mono_install_remoting_trampoline (mono_jit_create_remoting_trampoline);
        mono_install_delegate_trampoline (mono_create_delegate_trampoline);
@@ -5799,13 +5912,6 @@ mini_init (const char *filename, const char *runtime_version)
                        mono_install_imt_thunk_builder (mono_aot_get_imt_thunk);
                else
                        mono_install_imt_thunk_builder (mono_arch_build_imt_thunk);
-               if (!mono_use_llvm) {
-                       /* 
-                        * The imt code in mono_magic_trampoline () can't handle LLVM code. By disabling
-                        * this, we force iface calls to go through the llvm vcall trampoline.
-                        */
-                       mono_install_imt_trampoline (mini_get_imt_trampoline ());
-               }
        }
 #endif
 
@@ -5831,6 +5937,8 @@ mini_init (const char *filename, const char *runtime_version)
 
        create_helper_signature ();
 
+       register_jit_stats ();
+
 #define JIT_CALLS_WORK
 #ifdef JIT_CALLS_WORK
        /* Needs to be called here since register_jit_icall depends on it */
@@ -5847,9 +5955,6 @@ mini_init (const char *filename, const char *runtime_version)
 
        register_icall (mono_get_throw_exception (), "mono_arch_throw_exception", "void object", TRUE);
        register_icall (mono_get_rethrow_exception (), "mono_arch_rethrow_exception", "void object", TRUE);
-#ifdef MONO_ARCH_HAVE_THROW_EXCEPTION_BY_NAME
-       register_icall (mono_get_throw_exception_by_name (), "mono_arch_throw_exception_by_name", "void ptr", TRUE); 
-#endif
 #if MONO_ARCH_HAVE_THROW_CORLIB_EXCEPTION
        register_icall (mono_get_throw_corlib_exception (), "mono_arch_throw_corlib_exception", 
                                 "void ptr", TRUE);
@@ -6015,6 +6120,10 @@ mini_init (const char *filename, const char *runtime_version)
        register_icall (mono_array_new_2, "mono_array_new_2", "object ptr int int", FALSE);
        register_icall (mono_array_new_3, "mono_array_new_3", "object ptr int int int", FALSE);
        register_icall (mono_get_native_calli_wrapper, "mono_get_native_calli_wrapper", "ptr ptr ptr ptr", FALSE);
+       register_icall (mono_resume_unwind, "mono_resume_unwind", "void", TRUE);
+
+       register_icall (mono_gc_wbarrier_value_copy_bitmap, "mono_gc_wbarrier_value_copy_bitmap", "void ptr ptr int int", FALSE);
+
 #endif
 
        mono_generic_sharing_init ();
@@ -6055,10 +6164,7 @@ print_jit_stats (void)
 {
        if (mono_jit_stats.enabled) {
                g_print ("Mono Jit statistics\n");
-               g_print ("Compiled methods:       %ld\n", mono_jit_stats.methods_compiled);
-               g_print ("Methods from AOT:       %ld\n", mono_jit_stats.methods_aot);
                g_print ("Methods cache lookup:   %ld\n", mono_jit_stats.methods_lookups);
-               g_print ("Method trampolines:     %ld\n", mono_jit_stats.method_trampolines);
                g_print ("Basic blocks:           %ld\n", mono_jit_stats.basic_blocks);
                g_print ("Max basic blocks:       %ld\n", mono_jit_stats.max_basic_blocks);
                g_print ("Allocated vars:         %ld\n", mono_jit_stats.allocate_var);
@@ -6111,13 +6217,9 @@ print_jit_stats (void)
                g_print ("JIT info table lookups: %ld\n", mono_stats.jit_info_table_lookup_count);
 
                g_print ("Hazardous pointers:     %ld\n", mono_stats.hazardous_pointer_count);
-#ifdef HAVE_SGEN_GC
                g_print ("Minor GC collections:   %ld\n", mono_stats.minor_gc_count);
-#endif
                g_print ("Major GC collections:   %ld\n", mono_stats.major_gc_count);
-#ifdef HAVE_SGEN_GC
                g_print ("Minor GC time in msecs: %lf\n", (double)mono_stats.minor_gc_time_usecs / 1000.0);
-#endif
                g_print ("Major GC time in msecs: %lf\n", (double)mono_stats.major_gc_time_usecs / 1000.0);
                if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
                        g_print ("\nDecl security check   : %ld\n", mono_jit_stats.cas_declsec_check);
@@ -6145,6 +6247,7 @@ mini_cleanup (MonoDomain *domain)
 #endif
 
 #ifndef MONO_CROSS_COMPILE     
+       mono_runtime_shutdown ();
        /* 
         * mono_runtime_cleanup() and mono_domain_finalize () need to
         * be called early since they need the execution engine still
@@ -6172,9 +6275,12 @@ mini_cleanup (MonoDomain *domain)
        mono_debugger_cleanup ();
 
 #ifdef ENABLE_LLVM
-       mono_llvm_cleanup ();
+       if (mono_use_llvm)
+               mono_llvm_cleanup ();
 #endif
 
+       mono_aot_cleanup ();
+
        mono_trampolines_cleanup ();
 
        mono_unwind_cleanup ();
@@ -6184,6 +6290,7 @@ mini_cleanup (MonoDomain *domain)
        g_hash_table_destroy (jit_icall_name_hash);
        g_free (emul_opcode_map);
        g_free (emul_opcode_opcodes);
+       g_free (vtable_trampolines);
 
        mono_arch_cleanup ();