2005-01-26 Martin Baulig <martin@ximian.com>
[mono.git] / mono / mini / mini.c
index acf58969d4fc3e35fc334033cb505b9ba11d8558..6317fa546b806aaab691baa8becb8dd717c7fa70 100644 (file)
@@ -12,6 +12,7 @@
 #include <signal.h>
 #include <unistd.h>
 #include <math.h>
+#include <sys/time.h>
 
 #ifdef sun    // Solaris x86
 #include <sys/types.h>
@@ -46,6 +47,8 @@
 #include <mono/metadata/mono-debug.h>
 #include <mono/metadata/mono-debug-debugger.h>
 #include <mono/metadata/monitor.h>
+#include <mono/metadata/security-manager.h>
+#include <mono/utils/mono-math.h>
 #include <mono/os/gc_wrapper.h>
 
 #include "mini.h"
@@ -65,6 +68,7 @@
 
 #define MONO_CHECK_THIS(ins) (cfg->method->signature->hasthis && (ins)->ssa_op == MONO_SSA_LOAD && (ins)->inst_left->inst_c0 == 0)
 
+static void setup_stat_profiler (void);
 gboolean  mono_arch_print_tree(MonoInst *tree, int arity);
 static gpointer mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt);
 static gpointer mono_jit_compile_method (MonoMethod *method);
@@ -132,6 +136,7 @@ gboolean mono_break_on_exc = FALSE;
 #ifndef DISABLE_AOT
 gboolean mono_compile_aot = FALSE;
 #endif
+gboolean mono_use_security_manager = FALSE;
 
 static int mini_verbose = 0;
 
@@ -139,6 +144,10 @@ static CRITICAL_SECTION jit_mutex;
 
 static GHashTable *class_init_hash_addr = NULL;
 
+static MonoCodeManager *global_codeman = NULL;
+
+static GHashTable *jit_icall_name_hash = NULL;
+
 gboolean
 mono_running_on_valgrind (void)
 {
@@ -152,6 +161,31 @@ mono_running_on_valgrind (void)
 #endif
 }
 
+/* debug function */
+G_GNUC_UNUSED static char*
+get_method_from_ip (void *ip)
+{
+       MonoJitInfo *ji;
+       char *method;
+       char *source;
+       char *res;
+       MonoDomain *domain = mono_domain_get ();
+       
+       ji = mono_jit_info_table_find (domain, ip);
+       if (!ji) {
+               return NULL;
+       }
+       method = mono_method_full_name (ji->method, TRUE);
+       source = mono_debug_source_location_from_address (ji->method, (int) ip, NULL, domain);
+
+       res = g_strdup_printf (" %s + 0x%x (%p %p) [%p - %s]", method, (int)((char*)ip - (char*)ji->code_start), ji->code_start, (char*)ji->code_start + ji->code_size, domain, domain->friendly_name);
+
+       g_free (source);
+       g_free (method);
+
+       return res;
+}
+
 /* debug function */
 G_GNUC_UNUSED static void
 print_method_from_ip (void *ip)
@@ -176,7 +210,6 @@ print_method_from_ip (void *ip)
 
        g_free (source);
        g_free (method);
-
 }
 
 G_GNUC_UNUSED void
@@ -212,6 +245,28 @@ gboolean mono_method_same_domain (MonoJitInfo *caller, MonoJitInfo *callee)
        return TRUE;
 }
 
+/*
+ * mono_global_codeman_reserve:
+ *
+ *  Allocate code memory from the global code manager.
+ */
+void *mono_global_codeman_reserve (int size)
+{
+       void *ptr;
+
+       if (!global_codeman) {
+               /* This can happen during startup */
+               global_codeman = mono_code_manager_new ();
+               return mono_code_manager_reserve (global_codeman, size);
+       }
+       else {
+               EnterCriticalSection (&jit_mutex);
+               ptr = mono_code_manager_reserve (global_codeman, size);
+               LeaveCriticalSection (&jit_mutex);
+               return ptr;
+       }
+}
+
 MonoJumpInfoToken *
 mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
 {
@@ -264,12 +319,6 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
                (dest)->type = STACK_I4;        \
        } while (0)
 
-#if SIZEOF_VOID_P == 8
-#define OP_PCONST OP_I8CONST
-#else
-#define OP_PCONST OP_ICONST
-#endif
-
 #define NEW_PCONST(cfg,dest,val) do {  \
                (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
                (dest)->opcode = OP_PCONST;     \
@@ -289,8 +338,8 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
 
 #define NEW_AOTCONST(cfg,dest,patch_type,cons) do {    \
                (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
-               (dest)->opcode = mono_compile_aot ? OP_GOT_ENTRY : OP_PCONST;   \
-        if (mono_compile_aot) { \
+               (dest)->opcode = cfg->compile_aot ? OP_GOT_ENTRY : OP_PCONST;   \
+        if (cfg->compile_aot) { \
             MonoInst *group, *got_var; \
             NEW_TEMPLOAD ((cfg), got_var, mono_get_got_var (cfg)->inst_c0); \
                    NEW_PATCH_INFO ((cfg), group, cons, patch_type); \
@@ -319,7 +368,7 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
 
 #define NEW_AOTCONST(cfg,dest,patch_type,cons) do {    \
                (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
-               (dest)->opcode = mono_compile_aot ? OP_AOTCONST : OP_PCONST;    \
+               (dest)->opcode = cfg->compile_aot ? OP_AOTCONST : OP_PCONST;    \
                (dest)->inst_p0 = (cons);       \
                (dest)->inst_i1 = (gpointer)(patch_type); \
                (dest)->type = STACK_PTR;       \
@@ -343,7 +392,7 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
 
 #define NEW_METHODCONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_METHODCONST, (val))
 
-#define NEW_VTABLECONST(cfg,dest,vtable) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_VTABLE, mono_compile_aot ? (gpointer)((vtable)->klass) : (vtable))
+#define NEW_VTABLECONST(cfg,dest,vtable) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_VTABLE, cfg->compile_aot ? (gpointer)((vtable)->klass) : (vtable))
 
 #define NEW_SFLDACONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_SFLDA, (val))
 
@@ -353,6 +402,14 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
 
 #define NEW_LDTOKENCONST(cfg,dest,image,token) NEW_AOTCONST_TOKEN ((cfg), (dest), MONO_PATCH_INFO_LDTOKEN, (image), (token), STACK_PTR)
 
+#define NEW_DECLSECCONST(cfg,dest,image,entry) do { \
+               if (cfg->compile_aot) { \
+                       NEW_AOTCONST_TOKEN (cfg, dest, MONO_PATCH_INFO_DECLSEC, image, (entry).index, STACK_OBJ); \
+               } else { \
+                       NEW_PCONST (cfg, args [0], (entry).blob); \
+               } \
+       } while (0)
+
 #define NEW_DOMAINCONST(cfg,dest) do { \
                if (cfg->opt & MONO_OPT_SHARED) { \
                        NEW_TEMPLOAD (cfg, dest, mono_get_domainvar (cfg)->inst_c0); \
@@ -489,6 +546,13 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
                (dest)->inst_left = (load); \
     } while (0)
 
+#define NEW_DUMMY_STORE(cfg,dest,num) do { \
+               (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
+               (dest)->inst_i0 = (cfg)->varinfo [(num)];       \
+               (dest)->opcode = OP_DUMMY_STORE; \
+               (dest)->klass = (dest)->inst_i0->klass; \
+       } while (0)
+
 #define ADD_BINOP(op) do {     \
                MONO_INST_NEW (cfg, ins, (op)); \
                ins->cil_code = ip;     \
@@ -678,7 +742,7 @@ link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
  *   that is in none of try/catch/filter.
  */
 static int
-mono_find_block_region (MonoCompile *cfg, int offset, int *filter_lengths)
+mono_find_block_region (MonoCompile *cfg, int offset)
 {
        MonoMethod *method = cfg->method;
        MonoMethodHeader *header = mono_method_get_header (method);
@@ -689,7 +753,7 @@ mono_find_block_region (MonoCompile *cfg, int offset, int *filter_lengths)
        for (i = 0; i < header->num_clauses; ++i) {
                clause = &header->clauses [i];
                if ((clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->data.filter_offset) &&
-                   (offset < (clause->data.filter_offset + filter_lengths [i])))
+                   (offset < (clause->handler_offset)))
                        return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
                           
                if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
@@ -756,6 +820,30 @@ mono_create_spvar_for_region (MonoCompile *cfg, int region)
        g_hash_table_insert (cfg->spvars, GINT_TO_POINTER (region), var);
 }
 
+static MonoInst *
+mono_find_exvar_for_offset (MonoCompile *cfg, int offset)
+{
+       return g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
+}
+
+static MonoInst*
+mono_create_exvar_for_offset (MonoCompile *cfg, int offset)
+{
+       MonoInst *var;
+
+       var = g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
+       if (var)
+               return var;
+
+       var = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
+       /* prevent it from being register allocated */
+       var->flags |= MONO_INST_INDIRECT;
+
+       g_hash_table_insert (cfg->exvars, GINT_TO_POINTER (offset), var);
+
+       return var;
+}
+
 static void
 df_visit (MonoBasicBlock *start, int *dfn, MonoBasicBlock **array)
 {
@@ -852,6 +940,40 @@ split_bblock (MonoCompile *cfg, MonoBasicBlock *first, MonoBasicBlock *second) {
        }
 }
 
+static guint32
+reverse_branch_op (guint32 opcode)
+{
+       static const int reverse_map [] = {
+               CEE_BNE_UN, CEE_BLT, CEE_BLE, CEE_BGT, CEE_BGE,
+               CEE_BEQ, CEE_BLT_UN, CEE_BLE_UN, CEE_BGT_UN, CEE_BGE_UN
+       };
+       static const int reverse_fmap [] = {
+               OP_FBNE_UN, OP_FBLT, OP_FBLE, OP_FBGT, OP_FBGE,
+               OP_FBEQ, OP_FBLT_UN, OP_FBLE_UN, OP_FBGT_UN, OP_FBGE_UN
+       };
+       static const int reverse_lmap [] = {
+               OP_LBNE_UN, OP_LBLT, OP_LBLE, OP_LBGT, OP_LBGE,
+               OP_LBEQ, OP_LBLT_UN, OP_LBLE_UN, OP_LBGT_UN, OP_LBGE_UN
+       };
+       static const int reverse_imap [] = {
+               OP_IBNE_UN, OP_IBLT, OP_IBLE, OP_IBGT, OP_IBGE,
+               OP_IBEQ, OP_IBLT_UN, OP_IBLE_UN, OP_IBGT_UN, OP_IBGE_UN
+       };
+                               
+       if (opcode >= CEE_BEQ && opcode <= CEE_BLT_UN) {
+               opcode = reverse_map [opcode - CEE_BEQ];
+       } else if (opcode >= OP_FBEQ && opcode <= OP_FBLT_UN) {
+               opcode = reverse_fmap [opcode - OP_FBEQ];
+       } else if (opcode >= OP_LBEQ && opcode <= OP_LBLT_UN) {
+               opcode = reverse_lmap [opcode - OP_LBEQ];
+       } else if (opcode >= OP_IBEQ && opcode <= OP_IBLT_UN) {
+               opcode = reverse_imap [opcode - OP_IBEQ];
+       } else
+               g_assert_not_reached ();
+
+       return opcode;
+}
+
 guint
 mono_type_to_ldind (MonoType *type)
 {
@@ -1419,7 +1541,7 @@ inline static MonoInst *
 mono_get_got_var (MonoCompile *cfg)
 {
 #ifdef MONO_ARCH_NEED_GOT_VAR
-       if (!mono_compile_aot)
+       if (!cfg->compile_aot)
                return NULL;
        if (!cfg->got_var) {
                cfg->got_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
@@ -1889,25 +2011,6 @@ check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **arg
        }
        for (i = 0; i < sig->param_count; ++i) {
                if (sig->params [i]->byref) {
-                       /* 
-                        * check the result of ldelema is only passed as an argument if the byref
-                        * type matches exactly the array element type.
-                        * FIXME: if the argument as been saved on the stack as part of the
-                        * interface variable code (the value was on the stack at a basic block boundary)
-                        * we need to add the check in that case, too.
-                        */
-                       if (args [i]->opcode == CEE_LDELEMA) {
-                               MonoInst *check;
-                               MonoClass *exact_class = mono_class_from_mono_type (sig->params [i]);
-                               if (!exact_class->valuetype) {
-                                       MONO_INST_NEW (cfg, check, OP_CHECK_ARRAY_TYPE);
-                                       check->cil_code = args [i]->cil_code;
-                                       check->klass = exact_class;
-                                       check->inst_left = args [i]->inst_left;
-                                       check->type = STACK_OBJ;
-                                       args [i]->inst_left = check;
-                               }
-                       }
                        if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
                                return 1;
                        continue;
@@ -1997,7 +2100,17 @@ mono_spill_call (MonoCompile *cfg, MonoBasicBlock *bblock, MonoCallInst *call, M
                temp->flags |= MONO_INST_IS_TEMP;
 
                if (MONO_TYPE_ISSTRUCT (ret)) {
-                       MonoInst *loada;
+                       MonoInst *loada, *dummy_store;
+
+                       /* 
+                        * Emit a dummy store to the local holding the result so the
+                        * liveness info remains correct.
+                        */
+                       NEW_DUMMY_STORE (cfg, dummy_store, temp->inst_c0);
+                       if (to_end)
+                               mono_add_ins_to_end (bblock, dummy_store);
+                       else
+                               MONO_ADD_INS (bblock, dummy_store);
 
                        /* we use this to allocate native sized structs */
                        temp->unused = sig->pinvoke;
@@ -2089,7 +2202,9 @@ mono_emit_method_call (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *met
        call->inst.flags |= MONO_INST_HAS_METHOD;
        call->inst.inst_left = this;
 
-       if (virtual && (call->method->klass->flags & TYPE_ATTRIBUTE_INTERFACE))
+       if (!virtual)
+               mono_get_got_var (cfg);
+       else if (call->method->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
                /* Needed by the code generated in inssel.brg */
                mono_get_got_var (cfg);
 
@@ -2128,6 +2243,7 @@ mono_emit_jit_icall (MonoCompile *cfg, MonoBasicBlock *bblock, gconstpointer fun
                g_assert_not_reached ();
        }
 
+       mono_get_got_var (cfg);
        return mono_emit_native_call (cfg, bblock, mono_icall_get_wrapper (info), info->sig, args, ip, FALSE, FALSE);
 }
 
@@ -2150,6 +2266,8 @@ mono_emulate_opcode (MonoCompile *cfg, MonoInst *tree, MonoInst **iargs, MonoJit
 
        call = mono_arch_call_opcode (cfg, cfg->cbb, call, FALSE);
 
+       mono_get_got_var (cfg);
+
        if (!MONO_TYPE_IS_VOID (info->sig->ret)) {
                temp = mono_compile_create_var (cfg, info->sig->ret, OP_LOCAL);
                temp->flags |= MONO_INST_IS_TEMP;
@@ -2283,6 +2401,11 @@ handle_stobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, MonoInst
 
        if ((cfg->opt & MONO_OPT_INTRINS) && !to_end && n <= sizeof (gpointer) * 5) {
                MonoInst *inst;
+               if (dest->opcode == OP_LDADDR) {
+                       /* Keep liveness info correct */
+                       NEW_DUMMY_STORE (cfg, inst, dest->inst_i0->inst_c0);
+                       MONO_ADD_INS (bblock, inst);
+               }
                MONO_INST_NEW (cfg, inst, OP_MEMCPY);
                inst->inst_left = dest;
                inst->inst_right = src;
@@ -2406,6 +2529,7 @@ handle_array_new (MonoCompile *cfg, MonoBasicBlock *bblock, int rank, MonoInst *
 {
        MonoMethodSignature *esig;
        char icall_name [256];
+       char *name;
        MonoJitICallInfo *info;
 
        /* Need to register the icall so it gets an icall wrapper */
@@ -2414,7 +2538,12 @@ handle_array_new (MonoCompile *cfg, MonoBasicBlock *bblock, int rank, MonoInst *
        info = mono_find_jit_icall_by_name (icall_name);
        if (info == NULL) {
                esig = mono_get_array_new_va_signature (rank);
-               info = mono_register_jit_icall (mono_array_new_va, g_strdup (icall_name), esig, FALSE);
+               name = g_strdup (icall_name);
+               info = mono_register_jit_icall (mono_array_new_va, name, esig, FALSE);
+
+               EnterCriticalSection (&jit_mutex);
+               g_hash_table_insert (jit_icall_name_hash, name, name);
+               LeaveCriticalSection (&jit_mutex);
        }
 
        cfg->flags |= MONO_CFG_HAS_VARARGS;
@@ -2422,6 +2551,39 @@ handle_array_new (MonoCompile *cfg, MonoBasicBlock *bblock, int rank, MonoInst *
        return mono_emit_native_call (cfg, bblock, mono_icall_get_wrapper (info), info->sig, sp, ip, TRUE, FALSE);
 }
 
+static void
+mono_emit_load_got_addr (MonoCompile *cfg)
+{
+       MonoInst *load, *store, *dummy_use;
+       MonoInst *get_got;
+
+       if (!cfg->got_var || cfg->got_var_allocated)
+               return;
+
+       MONO_INST_NEW (cfg, get_got, OP_LOAD_GOTADDR);
+       NEW_TEMPSTORE (cfg, store, cfg->got_var->inst_c0, get_got);
+
+       /* Add it to the start of the first bblock */
+       if (cfg->bb_entry->code) {
+               store->next = cfg->bb_entry->code;
+               cfg->bb_entry->code = store;
+       }
+       else
+               MONO_ADD_INS (cfg->bb_entry, store);
+
+       cfg->got_var_allocated = TRUE;
+
+       /* 
+        * Add a dummy use to keep the got_var alive, since real uses might
+        * only be generated in the decompose or instruction selection phases.
+        * Add it to end_bblock, so the variable's lifetime covers the whole
+        * method.
+        */
+       NEW_TEMPLOAD (cfg, load, cfg->got_var->inst_c0);
+       NEW_DUMMY_USE (cfg, dummy_use, load);
+       MONO_ADD_INS (cfg->bb_exit, dummy_use);
+}
+
 #define CODE_IS_STLOC(ip) (((ip) [0] >= CEE_STLOC_0 && (ip) [0] <= CEE_STLOC_3) || ((ip) [0] == CEE_STLOC_S))
 
 static gboolean
@@ -2507,6 +2669,7 @@ mini_get_ldelema_ins (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *cmet
        MonoInst *addr;
        MonoMethodSignature *esig;
        char icall_name [256];
+       char *name;
        MonoJitICallInfo *info;
 
        rank = cmethod->signature->param_count - (is_set? 1: 0);
@@ -2529,7 +2692,12 @@ mini_get_ldelema_ins (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *cmet
        info = mono_find_jit_icall_by_name (icall_name);
        if (info == NULL) {
                esig = mono_get_element_address_signature (rank);
-               info = mono_register_jit_icall (ves_array_element_address, g_strdup (icall_name), esig, FALSE);
+               name = g_strdup (icall_name);
+               info = mono_register_jit_icall (ves_array_element_address, name, esig, FALSE);
+
+               EnterCriticalSection (&jit_mutex);
+               g_hash_table_insert (jit_icall_name_hash, name, name);
+               LeaveCriticalSection (&jit_mutex);
        }
 
        temp = mono_emit_native_call (cfg, bblock, mono_icall_get_wrapper (info), info->sig, sp, ip, FALSE, FALSE);
@@ -2580,6 +2748,10 @@ mini_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSigna
                        MONO_INST_NEW (cfg, ins, OP_GETTYPE);
                        ins->inst_i0 = args [0];
                        return ins;
+               } else if (strcmp (cmethod->name, "InternalGetHashCode") == 0) {
+                       MONO_INST_NEW (cfg, ins, OP_GETHASHCODE);
+                       ins->inst_i0 = args [0];
+                       return ins;
                } else
                        return NULL;
        } else if (cmethod->klass == mono_defaults.array_class) {
@@ -2866,6 +3038,17 @@ emit_tree (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ins, const guint8
        return load;
 }
 
+static inline MonoMethod *
+mini_get_method (MonoImage *image, guint32 token, MonoClass *klass, MonoGenericContext *context)
+{
+       MonoMethod *method = mono_get_method_full (image, token, klass, context);
+
+       if (method->is_inflated)
+               method = mono_get_inflated_method (method);
+
+       return method;
+}
+
 /*
  * mono_method_to_ir: translates IL into basic blocks containing trees
  */
@@ -2894,9 +3077,10 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
        GList *bb_recheck = NULL, *tmp;
        int i, n, start_new_bblock, align;
        int num_calls = 0, inline_costs = 0;
-       int *filter_lengths = NULL;
        int breakpoint_id = 0;
        guint real_offset, num_args;
+       MonoBoolean security;
+       MonoDeclSecurityActions actions;
 
        image = method->klass->image;
        header = mono_method_get_header (method);
@@ -2928,6 +3112,10 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
        dont_inline = g_list_prepend (dont_inline, method);
        if (cfg->method == method) {
 
+               if (cfg->method->save_lmf)
+                       /* Needed by the prolog code */
+                       mono_get_got_var (cfg);
+
                if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
                        cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
 
@@ -2949,11 +3137,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        arg_array [i] = cfg->varinfo [i];
 
                if (header->num_clauses) {
-                       int size = sizeof (int) * header->num_clauses;
-                       filter_lengths = alloca (size);
-                       memset (filter_lengths, 0, size);
-
                        cfg->spvars = g_hash_table_new (NULL, NULL);
+                       cfg->exvars = g_hash_table_new (NULL, NULL);
                }
                /* handle exception clauses */
                for (i = 0; i < header->num_clauses; ++i) {
@@ -2977,23 +3162,28 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        /* catch and filter blocks get the exception object on the stack */
                        if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
                            clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
+                               MonoInst *load, *dummy_use;
+
                                /* mostly like handle_stack_args (), but just sets the input args */
                                /* g_print ("handling clause at IL_%04x\n", clause->handler_offset); */
-                               if (!cfg->exvar) {
-                                       cfg->exvar = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
-                                       /* prevent it from being register allocated */
-                                       cfg->exvar->flags |= MONO_INST_INDIRECT;
-                               }
                                tblock->in_scount = 1;
                                tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
-                               tblock->in_stack [0] = cfg->exvar;
+                               tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
+
+                               /* 
+                                * Add a dummy use for the exvar so its liveness info will be
+                                * correct.
+                                */
+                               NEW_TEMPLOAD (cfg, load, tblock->in_stack [0]->inst_c0);
+                               NEW_DUMMY_USE (cfg, dummy_use, load);
+                               MONO_ADD_INS (tblock, dummy_use);
                                
                                if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
                                        GET_BBLOCK (cfg, bbhash, tblock, ip + clause->data.filter_offset);
                                        tblock->real_offset = clause->data.filter_offset;
                                        tblock->in_scount = 1;
                                        tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
-                                       tblock->in_stack [0] = cfg->exvar;
+                                       tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->data.filter_offset);
                                        MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
                                        MONO_ADD_INS (tblock, ins);
                                }
@@ -3017,8 +3207,17 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        MONO_ADD_INS (bblock, ins);
                }
        }
+
+       security = mono_use_security_manager && mono_method_has_declsec (method);
+       /* at this point having security doesn't mean we have any code to generate */
+       if (security && (cfg->method == method)) {
+               /* Only Demand, NonCasDemand and DemandChoice requires code generation.
+                * And we do not want to enter the next section (with allocation) if we
+                * have nothing to generate */
+               security = mono_declsec_get_demands (method, &actions);
+       }
        
-       if ((header->init_locals || (cfg->method == method && (cfg->opt & MONO_OPT_SHARED))) || mono_compile_aot) {
+       if ((header->init_locals || (cfg->method == method && (cfg->opt & MONO_OPT_SHARED))) || mono_compile_aot || security) {
                /* we use a separate basic block for the initialization code */
                cfg->bb_init = init_localsbb = NEW_BBLOCK (cfg);
                init_localsbb->real_offset = real_offset;
@@ -3032,6 +3231,35 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                link_bblock (cfg, start_bblock, bblock);
        }
 
+       /* at this point we know, if security is TRUE, that some code needs to be generated */
+       if (security && (cfg->method == method)) {
+               MonoInst *args [2];
+               MonoSecurityManager* secman = mono_security_manager_get_methods ();
+
+               if (actions.demand.blob) {
+                       /* Add code for SecurityAction.Demand */
+                       NEW_DECLSECCONST (cfg, args[0], image, actions.demand);
+                       NEW_ICONST (cfg, args [1], actions.demand.size);
+                       /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
+                       mono_emit_method_call_spilled (cfg, init_localsbb, secman->demand, secman->demand->signature, args, ip, NULL);
+               }
+               if (actions.noncasdemand.blob) {
+                       /* CLR 1.x uses a .noncasdemand (but 2.x doesn't) */
+                       /* For Mono we re-route non-CAS Demand to Demand (as the managed code must deal with it anyway) */
+                       NEW_DECLSECCONST (cfg, args[0], image, actions.noncasdemand);
+                       NEW_ICONST (cfg, args [1], actions.noncasdemand.size);
+                       /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
+                       mono_emit_method_call_spilled (cfg, init_localsbb, secman->demand, secman->demand->signature, args, ip, NULL);
+               }
+               if (actions.demandchoice.blob) {
+                       /* New in 2.0, Demand must succeed for one of the permissions (i.e. not all) */
+                       NEW_DECLSECCONST (cfg, args[0], image, actions.demandchoice);
+                       NEW_ICONST (cfg, args [1], actions.demandchoice.size);
+                       /* Calls static void SecurityManager.InternalDemandChoice (byte* permissions, int size); */
+                       mono_emit_method_call_spilled (cfg, init_localsbb, secman->demandchoice, secman->demandchoice->signature, args, ip, NULL);
+               }
+       }
+
        if (get_basic_blocks (cfg, bbhash, header, real_offset, ip, end, &err_pos)) {
                ip = err_pos;
                goto unverified;
@@ -3321,6 +3549,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        ++ip;
                        readr4 (ip, f);
                        ins->inst_p0 = f;
+
                        ip += 4;
                        *sp++ = ins;                    
                        break;
@@ -3334,6 +3563,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        ++ip;
                        readr8 (ip, d);
                        ins->inst_p0 = d;
+
                        ip += 8;
                        *sp++ = ins;                    
                        break;
@@ -3431,7 +3661,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        MONO_INST_NEW (cfg, ins, CEE_JMP);
                        token = read32 (ip + 1);
                        /* FIXME: check the signature matches */
-                       cmethod = mono_get_method_full (image, token, NULL, generic_context);
+                       cmethod = mini_get_method (image, token, NULL, generic_context);
                        ins->inst_p0 = cmethod;
                        MONO_ADD_INS (bblock, ins);
                        ip += 5;
@@ -3464,8 +3694,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        cmethod =  (MonoMethod *)mono_method_get_wrapper_data (method, token);
                                } else if (constrained_call) {
                                        cmethod = mono_get_method_constrained (image, token, constrained_call, generic_context);
+                                       cmethod = mono_get_inflated_method (cmethod);
                                } else {
-                                       cmethod = mono_get_method_full (image, token, NULL, generic_context);
+                                       cmethod = mini_get_method (image, token, NULL, generic_context);
                                }
 
                                g_assert (cmethod);
@@ -3494,8 +3725,20 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                        }
 
-                       if (cmethod && cmethod->klass->generic_container)
+                       if (!virtual) {
+                               mono_get_got_var (cfg);
+                       } else {
+                               /* code in inssel.brg might transform a virtual call to a normal call */
+                               if (!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || 
+                                       ((cmethod->flags & METHOD_ATTRIBUTE_FINAL) && 
+                                        cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK))
+                                       mono_get_got_var (cfg);
+                       }
+
+                       if (cmethod && cmethod->klass->generic_container) {
+                               G_BREAKPOINT ();
                                goto unverified;
+                       }
 
                        CHECK_STACK (n);
 
@@ -3540,8 +3783,10 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                constrained_call = NULL;
                        }
 
-                       if (*ip != CEE_CALLI && check_call_signature (cfg, fsig, sp))
+                       if (*ip != CEE_CALLI && check_call_signature (cfg, fsig, sp)) {
+                               G_BREAKPOINT ();
                                goto unverified;
+                       }
 
                        if (cmethod && virtual && cmethod->signature->generic_param_count) {
                                MonoInst *this_temp, *store;
@@ -4263,7 +4508,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        int temp;
                                        MonoInst *iargs [3];
 
-                                       if (mono_compile_aot) {
+                                       if (cfg->compile_aot) {
                                                cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
                                        }
 
@@ -4274,7 +4519,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        NEW_TEMPLOAD (cfg, *sp, temp);
                                        mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
                                } else {
-                                       if (mono_compile_aot)
+                                       if (cfg->compile_aot)
                                                NEW_LDSTRCONST (cfg, ins, image, n);
                                        else {
                                                NEW_PCONST (cfg, ins, NULL);
@@ -4299,7 +4544,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (method->wrapper_type != MONO_WRAPPER_NONE) {
                                cmethod = mono_method_get_wrapper_data (method, token);
                        } else
-                               cmethod = mono_get_method_full (image, token, NULL, generic_context);
+                               cmethod = mini_get_method (image, token, NULL, generic_context);
                        fsig = mono_method_get_signature (cmethod, image, token);
 
                        mono_class_init (cmethod->klass);
@@ -4483,8 +4728,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        ins->inst_newa_class = klass;
                                        ins->cil_code = ip;
                                        *sp++ = ins;
+                                       ip += 5;
                                }
-                               ip += 5;
                                break;
                        }
 
@@ -4620,6 +4865,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        --sp;
                        ins->inst_left = *sp;
                        ins->cil_code = ip++;
+                       bblock->out_of_line = TRUE;
                        MONO_ADD_INS (bblock, ins);
                        sp = stack_start;
                        link_bblock (cfg, bblock, end_bblock);
@@ -4717,7 +4963,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        NEW_CLASSCONST (cfg, iargs [1], klass);
                                        NEW_FIELDCONST (cfg, iargs [2], field);
                                        NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
-                                       if (cfg->opt & MONO_OPT_INLINE) {
+                                       if ((cfg->opt & MONO_OPT_INLINE) && !MONO_TYPE_ISSTRUCT (ldfld_wrapper->signature->ret)) {
                                                costs = inline_method (cfg, ldfld_wrapper, ldfld_wrapper->signature, bblock, 
                                                                       iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
                                                g_assert (costs > 0);
@@ -4804,7 +5050,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (cfg->domain->special_static_fields)
                                addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
 
-                       if ((cfg->opt & MONO_OPT_SHARED) || (mono_compile_aot && addr)) {
+                       if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
                                int temp;
                                MonoInst *iargs [2];
                                g_assert (field->parent);
@@ -4816,7 +5062,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                MonoVTable *vtable;
                                vtable = mono_class_vtable (cfg->domain, klass);
                                if (!addr) {
-                                       if ((!vtable->initialized || mono_compile_aot) && !(klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) && mono_class_needs_cctor_run (klass, method)) {
+                                       if ((!vtable->initialized || cfg->compile_aot) && !(klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) && mono_class_needs_cctor_run (klass, method)) {
                                                guint8 *tramp = mono_create_class_init_trampoline (vtable);
                                                mono_emit_native_call (cfg, bblock, tramp, 
                                                                                           helper_sig_class_init_trampoline,
@@ -4829,7 +5075,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        }
                                        addr = (char*)vtable->data + field->offset;
 
-                                       if (mono_compile_aot)
+                                       if (cfg->compile_aot)
                                                NEW_SFLDACONST (cfg, ins, field);
                                        else
                                                NEW_PCONST (cfg, ins, addr);
@@ -4869,12 +5115,16 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        } else {
                                gboolean is_const = FALSE;
                                MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
-                               if (!((cfg->opt & MONO_OPT_SHARED) || mono_compile_aot) && 
+                               if (!((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && 
                                    vtable->initialized && (field->type->attrs & FIELD_ATTRIBUTE_INIT_ONLY)) {
                                        gpointer addr = (char*)vtable->data + field->offset;
+                                       int ro_type = field->type->type;
+                                       if (ro_type == MONO_TYPE_VALUETYPE && field->type->data.klass->enumtype) {
+                                               ro_type = field->type->data.klass->enum_basetype->type;
+                                       }
                                        /* g_print ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, field->name);*/
                                        is_const = TRUE;
-                                       switch (field->type->type) {
+                                       switch (ro_type) {
                                        case MONO_TYPE_BOOLEAN:
                                        case MONO_TYPE_U1:
                                                NEW_ICONST (cfg, *sp, *((guint8 *)addr));
@@ -5063,6 +5313,21 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                klass = (MonoClass*)mono_method_get_wrapper_data (method, read32 (ip + 1));
                        else
                                klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
+                       
+                       /* we need to make sure that this array is exactly the type it needs
+                        * to be for correctness. the wrappers are lax with their usage
+                        * so we need to ignore them here
+                        */
+                       if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE) {
+                               MonoInst* check;
+                               MONO_INST_NEW (cfg, check, OP_CHECK_ARRAY_TYPE);
+                               check->cil_code = ip;
+                               check->klass = klass;
+                               check->inst_left = sp [0];
+                               check->type = STACK_OBJ;
+                               sp [0] = check;
+                       }
+                       
                        mono_class_init (klass);
                        NEW_LDELEMA (cfg, ins, sp, klass);
                        ins->cil_code = ip;
@@ -5308,12 +5573,12 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                MONO_ADD_INS (bblock, store);
                                NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
                        } else {
-                               if ((ip [5] == CEE_CALL) && (cmethod = mono_get_method_full (image, read32 (ip + 6), NULL, generic_context)) &&
+                               if ((ip [5] == CEE_CALL) && (cmethod = mini_get_method (image, read32 (ip + 6), NULL, generic_context)) &&
                                                (cmethod->klass == mono_defaults.monotype_class->parent) &&
                                                (strcmp (cmethod->name, "GetTypeFromHandle") == 0) && ip_in_bb (cfg, bblock, ip + 5)) {
                                        MonoClass *tclass = mono_class_from_mono_type (handle);
                                        mono_class_init (tclass);
-                                       if (mono_compile_aot)
+                                       if (cfg->compile_aot)
                                                NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n);
                                        else
                                                NEW_PCONST (cfg, ins, mono_type_get_object (cfg->domain, handle));
@@ -5323,7 +5588,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                } else {
                                        MonoInst *store, *addr, *vtvar;
 
-                                       if (mono_compile_aot)
+                                       if (cfg->compile_aot)
                                                NEW_LDTOKENCONST (cfg, ins, image, n);
                                        else
                                                NEW_PCONST (cfg, ins, handle);
@@ -5381,6 +5646,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                case CEE_LEAVE:
                case CEE_LEAVE_S: {
                        GList *handlers;
+
                        if (*ip == CEE_LEAVE) {
                                CHECK_OPSIZE (5);
                                target = ip + 5 + (gint32)read32(ip + 1);
@@ -5404,14 +5670,20 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                         */
                        for (i = 0; i < header->num_clauses; ++i) {
                                MonoExceptionClause *clause = &header->clauses [i];
-                               if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code)) {
+
+                               if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && (clause->flags == MONO_EXCEPTION_CLAUSE_NONE) && (ip - header->code + ((*ip == CEE_LEAVE) ? 5 : 2)) == (clause->handler_offset + clause->handler_len)) {
                                        int temp;
+                                       MonoInst *load;
+
+                                       NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
+                                       load->cil_code = ip;
 
                                        temp = mono_emit_jit_icall (cfg, bblock, mono_thread_get_pending_exception, NULL, ip);
                                        NEW_TEMPLOAD (cfg, *sp, temp);
-
+                               
                                        MONO_INST_NEW (cfg, ins, OP_THROW_OR_NULL);
                                        ins->inst_left = *sp;
+                                       ins->inst_right = load;
                                        ins->cil_code = ip;
                                        MONO_ADD_INS (bblock, ins);
                                }
@@ -5505,6 +5777,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                *sp++ = ins;
                                ip += 6;
                                inline_costs += 10 * num_calls++;
+                               /* Can't embed random pointers into AOT code */
+                               cfg->disable_aot = 1;
                                break;
                        case CEE_MONO_VTADDR:
                                CHECK_STACK (1);
@@ -5604,6 +5878,16 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 #endif
                                ip += 2;
                                break;
+                       case CEE_MONO_CLASSCONST:
+                               CHECK_STACK_OVF (1);
+                               CHECK_OPSIZE (6);
+                               token = read32 (ip + 2);
+                               NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
+                               ins->cil_code = ip;
+                               *sp++ = ins;
+                               ip += 6;
+                               inline_costs += 10 * num_calls++;
+                               break;
                        default:
                                g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
                                break;
@@ -5683,7 +5967,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                if (method->wrapper_type != MONO_WRAPPER_NONE)
                                        cmethod = mono_method_get_wrapper_data (method, n);
                                else {
-                                       cmethod = mono_get_method_full (image, n, NULL, generic_context);
+                                       cmethod = mini_get_method (image, n, NULL, generic_context);
                                }
 
                                mono_class_init (cmethod->klass);
@@ -5711,7 +5995,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                if (method->wrapper_type != MONO_WRAPPER_NONE)
                                        cmethod = mono_method_get_wrapper_data (method, n);
                                else
-                                       cmethod = mono_get_method_full (image, n, NULL, generic_context);
+                                       cmethod = mini_get_method (image, n, NULL, generic_context);
 
                                mono_class_init (cmethod->klass);
                                handle_loaded_temps (cfg, bblock, stack_start, sp);
@@ -5851,7 +6135,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        }
                                }
                                g_assert (nearest);
-                               filter_lengths [nearest_num] = (ip - header->code) -  nearest->data.filter_offset;
+                               if ((ip - header->code) != nearest->handler_offset)
+                                       goto unverified;
 
                                break;
                        }
@@ -5947,8 +6232,17 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                break;
                        case CEE_RETHROW: {
                                MonoInst *load;
-                               /* FIXME: check we are in a catch handler */
-                               NEW_TEMPLOAD (cfg, load, cfg->exvar->inst_c0);
+                               int handler_offset = -1;
+
+                               for (i = 0; i < header->num_clauses; ++i) {
+                                       MonoExceptionClause *clause = &header->clauses [i];
+                                       if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY))
+                                               handler_offset = clause->handler_offset;
+                               }
+
+                               g_assert (handler_offset != -1);
+
+                               NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
                                load->cil_code = ip;
                                MONO_INST_NEW (cfg, ins, OP_RETHROW);
                                ins->inst_left = load;
@@ -6026,23 +6320,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                MONO_ADD_INS (init_localsbb, store);
        }
 
-       if (cfg->method == method && cfg->got_var) {
-               MonoInst *load, *store, *dummy_use;
-               MonoInst *get_got;
-               MONO_INST_NEW (cfg, get_got, OP_LOAD_GOTADDR);
-               NEW_TEMPSTORE (cfg, store, cfg->got_var->inst_c0, get_got);
-               MONO_ADD_INS (init_localsbb, store);
-
-               /* 
-                * Add a dummy use to keep the got_var alive, since real uses might
-                * only be generated in the decompose or instruction selection phases.
-                * Add it to end_bblock, so the variable's lifetime covers the whole
-                * method.
-                */
-               NEW_TEMPLOAD (cfg, load, cfg->got_var->inst_c0);
-               NEW_DUMMY_USE (cfg, dummy_use, load);
-               MONO_ADD_INS (end_bblock, dummy_use);
-       }
+       if (cfg->method == method && cfg->got_var)
+               mono_emit_load_got_addr (cfg);
 
        if (header->init_locals) {
                MonoInst *store;
@@ -6081,7 +6360,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                }
        }
 
-       
        /* resolve backward branches in the middle of an existing basic block */
        for (tmp = bb_recheck; tmp; tmp = tmp->next) {
                bblock = tmp->data;
@@ -6098,14 +6376,10 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                }
        }
 
-       /*
-        * we compute regions here, because the length of filter clauses is not known in advance.
-        * It is computed in the CEE_ENDFILTER case in the above switch statement
-        */
        if (cfg->method == method) {
                MonoBasicBlock *bb;
                for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
-                       bb->region = mono_find_block_region (cfg, bb->real_offset, filter_lengths);
+                       bb->region = mono_find_block_region (cfg, bb->real_offset);
                        if (cfg->spvars)
                                mono_create_spvar_for_region (cfg, bb->region);
                        if (cfg->verbose_level > 2)
@@ -6424,7 +6698,7 @@ mono_create_class_init_trampoline (MonoVTable *vtable)
        /* previously created trampoline code */
        mono_domain_lock (vtable->domain);
        code = 
-               mono_g_hash_table_lookup (vtable->domain->class_init_trampoline_hash,
+               g_hash_table_lookup (vtable->domain->class_init_trampoline_hash,
                                                                  vtable);
        mono_domain_unlock (vtable->domain);
        if (code)
@@ -6434,7 +6708,7 @@ mono_create_class_init_trampoline (MonoVTable *vtable)
 
        /* store trampoline address */
        mono_domain_lock (vtable->domain);
-       mono_g_hash_table_insert (vtable->domain->class_init_trampoline_hash,
+       g_hash_table_insert (vtable->domain->class_init_trampoline_hash,
                                                          vtable, code);
        mono_domain_unlock (vtable->domain);
 
@@ -6462,7 +6736,7 @@ mono_create_jump_trampoline (MonoDomain *domain, MonoMethod *method,
                return code;
 
        mono_domain_lock (domain);
-       code = mono_g_hash_table_lookup (domain->jump_trampoline_hash, method);
+       code = g_hash_table_lookup (domain->jump_trampoline_hash, method);
        mono_domain_unlock (domain);
        if (code)
                return code;
@@ -6477,7 +6751,7 @@ mono_create_jump_trampoline (MonoDomain *domain, MonoMethod *method,
        mono_jit_info_table_add (mono_get_root_domain (), ji);
 
        mono_domain_lock (domain);
-       mono_g_hash_table_insert (domain->jump_trampoline_hash, method, ji->code_start);
+       g_hash_table_insert (domain->jump_trampoline_hash, method, ji->code_start);
        mono_domain_unlock (domain);
 
        return ji->code_start;
@@ -6539,6 +6813,162 @@ mono_dynamic_code_hash_lookup (MonoDomain *domain, MonoMethod *method)
        return res;
 }
 
+typedef struct {
+       MonoClass *vtype;
+       GList *active;
+       GList *slots;
+} StackSlotInfo;
+
+/*
+ * mono_allocate_stack_slots:
+ *
+ *  Allocate stack slots for all non register allocated variables using a
+ * linear scan algorithm.
+ * Returns: an array of stack offsets which the caller should free.
+ * STACK_SIZE is set to the amount of stack space needed.
+ * STACK_ALIGN is set to the alignment needed by the locals area.
+ */
+gint32*
+mono_allocate_stack_slots (MonoCompile *m, guint32 *stack_size, guint32 *stack_align)
+{
+       int i, slot, offset, size, align;
+       MonoMethodVar *vmv;
+       MonoInst *inst;
+       gint32 *offsets;
+       GList *vars = NULL, *l;
+       StackSlotInfo *scalar_stack_slots, *vtype_stack_slots, *slot_info;
+       MonoType *t;
+       int nvtypes;
+
+       scalar_stack_slots = g_new0 (StackSlotInfo, MONO_TYPE_PINNED);
+       vtype_stack_slots = g_new0 (StackSlotInfo, 256);
+       nvtypes = 0;
+
+       offsets = g_new (guint32, m->num_varinfo);
+       for (i = 0; i < m->num_varinfo; ++i)
+               offsets [i] = -1;
+
+       for (i = m->locals_start; i < m->num_varinfo; i++) {
+               inst = m->varinfo [i];
+               vmv = MONO_VARINFO (m, i);
+
+               if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR || inst->opcode == OP_REGOFFSET)
+                       continue;
+
+               vars = g_list_prepend (vars, vmv);
+       }
+
+       vars = mono_varlist_sort (m, vars, 0);
+       offset = 0;
+       *stack_align = 0;
+       for (l = vars; l; l = l->next) {
+               vmv = l->data;
+               inst = m->varinfo [vmv->idx];
+
+               /* inst->unused indicates native sized value types, this is used by the
+               * pinvoke wrappers when they call functions returning structures */
+               if (inst->unused && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
+                       size = mono_class_native_size (inst->inst_vtype->data.klass, &align);
+               else
+                       size = mono_type_size (inst->inst_vtype, &align);
+
+               t = mono_type_get_underlying_type (inst->inst_vtype);
+               switch (t->type) {
+               case MONO_TYPE_VALUETYPE:
+                       for (i = 0; i < nvtypes; ++i)
+                               if (t->data.klass == vtype_stack_slots [i].vtype)
+                                       break;
+                       if (i < nvtypes)
+                               slot_info = &vtype_stack_slots [i];
+                       else {
+                               g_assert (nvtypes < 256);
+                               vtype_stack_slots [nvtypes].vtype = t->data.klass;
+                               slot_info = &vtype_stack_slots [nvtypes];
+                               nvtypes ++;
+                       }
+                       break;
+               default:
+                       slot_info = &scalar_stack_slots [t->type];
+               }
+
+               slot = 0xffffff;
+               if (m->comp_done & MONO_COMP_LIVENESS) {
+                       //printf ("START  %2d %08x %08x\n",  vmv->idx, vmv->range.first_use.abs_pos, vmv->range.last_use.abs_pos);
+                       
+                       /* expire old intervals in active */
+                       while (slot_info->active) {
+                               MonoMethodVar *amv = (MonoMethodVar *)slot_info->active->data;
+
+                               if (amv->range.last_use.abs_pos > vmv->range.first_use.abs_pos)
+                                       break;
+
+                               //printf ("EXPIR  %2d %08x %08x C%d R%d\n", amv->idx, amv->range.first_use.abs_pos, amv->range.last_use.abs_pos, amv->spill_costs, amv->reg);
+
+                               slot_info->active = g_list_delete_link (slot_info->active, slot_info->active);
+                               slot_info->slots = g_list_prepend (slot_info->slots, GINT_TO_POINTER (offsets [amv->idx]));
+                       }
+
+                       /* 
+                        * This also handles the case when the variable is used in an
+                        * exception region, as liveness info is not computed there.
+                        */
+                       /* 
+                        * FIXME: All valuetypes are marked as INDIRECT because of LDADDR
+                        * opcodes.
+                        */
+                       if (! (inst->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT))) {
+                               if (slot_info->slots) {
+                                       slot = (int)slot_info->slots->data;
+
+                                       slot_info->slots = g_list_delete_link (slot_info->slots, slot_info->slots);
+                               }
+
+                               slot_info->active = mono_varlist_insert_sorted (m, slot_info->active, vmv, TRUE);
+                       }
+               }
+
+               {
+                       static int count = 0;
+                       count ++;
+
+                       /*
+                       if (count == atoi (getenv ("COUNT")))
+                               printf ("LAST: %s\n", mono_method_full_name (m->method, TRUE));
+                       if (count > atoi (getenv ("COUNT")))
+                               slot = 0xffffff;
+                       else {
+                               mono_print_tree_nl (inst);
+                               }
+                       */
+               }
+               if (slot == 0xffffff) {
+                       offset += size;
+                       offset += align - 1;
+                       offset &= ~(align - 1);
+                       slot = offset;
+
+                       if (*stack_align == 0)
+                               *stack_align = align;
+               }
+
+               offsets [vmv->idx] = slot;
+       }
+       g_list_free (vars);
+       for (i = 0; i < MONO_TYPE_PINNED; ++i) {
+               g_list_free (scalar_stack_slots [i].active);
+               g_list_free (scalar_stack_slots [i].slots);
+       }
+       for (i = 0; i < nvtypes; ++i) {
+               g_list_free (vtype_stack_slots [i].active);
+               g_list_free (vtype_stack_slots [i].slots);
+       }
+       g_free (scalar_stack_slots);
+       g_free (vtype_stack_slots);
+
+       *stack_size = offset;
+       return offsets;
+}
+
 void
 mono_register_opcode_emulation (int opcode, const char *name, MonoMethodSignature *sig, gpointer func, gboolean no_throw)
 {
@@ -6717,6 +7147,8 @@ mono_destroy_compile (MonoCompile *cfg)
                mono_regstate_free (cfg->rs);
        if (cfg->spvars)
                g_hash_table_destroy (cfg->spvars);
+       if (cfg->exvars)
+               g_hash_table_destroy (cfg->exvars);
        mono_mempool_destroy (cfg->mempool);
        g_list_free (cfg->ldstr_list);
 
@@ -6801,6 +7233,8 @@ mono_thread_start_cb (guint32 tid, gpointer stack_start, gpointer func)
        thread = mono_thread_current ();
        if (thread)
                thread->jit_data = jit_tls;
+       if (mono_profiler_get_events () & MONO_PROFILE_STATISTICAL)
+               setup_stat_profiler ();
 }
 
 void (*mono_thread_attach_aborted_cb ) (MonoObject *obj) = NULL;
@@ -6939,7 +7373,7 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
                break;
        case MONO_PATCH_INFO_IID:
                mono_class_init (patch_info->data.klass);
-               target = GINT_TO_POINTER (patch_info->data.klass->interface_id);
+               target = GINT_TO_POINTER ((int)patch_info->data.klass->interface_id);
                break;
        case MONO_PATCH_INFO_VTABLE:
                target = mono_class_vtable (domain, patch_info->data.klass);
@@ -6995,6 +7429,9 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
                target = handle;
                break;
        }
+       case MONO_PATCH_INFO_DECLSEC:
+               target = (mono_metadata_blob_heap (patch_info->data.token->image, patch_info->data.token->token) + 2);
+               break;
        case MONO_PATCH_INFO_BB_OVF:
        case MONO_PATCH_INFO_EXC_OVF:
        case MONO_PATCH_INFO_GOT_OFFSET:
@@ -7133,6 +7570,90 @@ replace_in_block (MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBlock *repl
        }
 }
 
+static void 
+replace_or_add_in_block (MonoCompile *cfg, MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBlock *repl)
+{
+       gboolean found = FALSE;
+       int i;
+
+       for (i = 0; i < bb->in_count; i++) {
+               MonoBasicBlock *ib = bb->in_bb [i];
+               if (ib == orig) {
+                       if (!repl) {
+                               if (bb->in_count > 1) {
+                                       bb->in_bb [i] = bb->in_bb [bb->in_count - 1];
+                               }
+                               bb->in_count--;
+                       } else {
+                               bb->in_bb [i] = repl;
+                       }
+                       found = TRUE;
+               }
+       }
+       
+       if (! found) {
+               MonoBasicBlock **new_in_bb = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * (bb->in_count + 1));
+               for (i = 0; i < bb->in_count; i++) {
+                       new_in_bb [i] = bb->in_bb [i];
+               }
+               new_in_bb [i] = repl;
+               bb->in_count++;
+               bb->in_bb = new_in_bb;
+       }
+}
+
+
+static void
+replace_out_block_in_code (MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBlock *repl) {
+       MonoInst *inst;
+       
+       for (inst = bb->code; inst != NULL; inst = inst->next) {
+               if (inst->opcode == OP_CALL_HANDLER) {
+                       if (inst->inst_target_bb == orig) {
+                               inst->inst_target_bb = repl;
+                       }
+               }
+       }
+       if (bb->last_ins != NULL) {
+               switch (bb->last_ins->opcode) {
+               case CEE_BR:
+                       if (bb->last_ins->inst_target_bb == orig) {
+                               bb->last_ins->inst_target_bb = repl;
+                       }
+                       break;
+               case CEE_SWITCH: {
+                       int i;
+                       int n = GPOINTER_TO_INT (bb->last_ins->klass);
+                       for (i = 0; i < n; i++ ) {
+                               if (bb->last_ins->inst_many_bb [i] == orig) {
+                                       bb->last_ins->inst_many_bb [i] = repl;
+                               }
+                       }
+                       break;
+               }
+               case CEE_BNE_UN:
+               case CEE_BEQ:
+               case CEE_BLT:
+               case CEE_BLT_UN:
+               case CEE_BGT:
+               case CEE_BGT_UN:
+               case CEE_BGE:
+               case CEE_BGE_UN:
+               case CEE_BLE:
+               case CEE_BLE_UN:
+                       if (bb->last_ins->inst_true_bb == orig) {
+                               bb->last_ins->inst_true_bb = repl;
+                       }
+                       if (bb->last_ins->inst_false_bb == orig) {
+                               bb->last_ins->inst_false_bb = repl;
+                       }
+                       break;
+               default:
+                       break;
+               }
+       }
+}
+
 static void 
 replace_basic_block (MonoBasicBlock *bb, MonoBasicBlock *orig,  MonoBasicBlock *repl)
 {
@@ -7149,6 +7670,96 @@ replace_basic_block (MonoBasicBlock *bb, MonoBasicBlock *orig,  MonoBasicBlock *
 
 }
 
+/**
+  * Check if a bb is useless (is just made of NOPs and ends with an
+  * unconditional branch, or nothing).
+  * If it is so, unlink it from the CFG and nullify it, and return TRUE.
+  * Otherwise, return FALSE;
+  */
+static gboolean
+remove_block_if_useless (MonoCompile *cfg, MonoBasicBlock *bb, MonoBasicBlock *previous_bb) {
+       MonoBasicBlock *target_bb = NULL;
+       MonoInst *inst;
+       
+       /* Do not touch handlers */
+       if (bb->region != -1) return FALSE;
+       
+       for (inst = bb->code; inst != NULL; inst = inst->next) {
+               switch (inst->opcode) {
+               case CEE_NOP:
+                       break;
+               case CEE_BR:
+                       target_bb = inst->inst_target_bb;
+                       break;
+               default:
+                       return FALSE;
+               }
+       }
+       
+       if (target_bb == NULL) {
+               if ((bb->out_count == 1) && (bb->out_bb [0] == bb->next_bb)) {
+                       target_bb = bb->next_bb;
+               } else {
+                       /* Do not touch empty BBs that do not "fall through" to their next BB (like the exit BB) */
+                       return FALSE;
+               }
+       }
+       
+       /* Do not touch BBs following a switch (they are the "default" branch) */
+       if ((previous_bb->last_ins != NULL) && (previous_bb->last_ins->opcode == CEE_SWITCH)) {
+               return FALSE;
+       }
+       
+       /* Do not touch BBs following the entry BB and jumping to something that is not */
+       /* thiry "next" bb (the entry BB cannot contain the branch) */
+       if ((previous_bb == cfg->bb_entry) && (bb->next_bb != target_bb)) {
+               return FALSE;
+       }
+       
+       if (target_bb != NULL) {
+               int i;
+               
+               if (cfg->verbose_level > 0) {
+                       printf ("remove_block_if_useless %s, removed BB%d\n", mono_method_full_name (cfg->method, TRUE), bb->block_num);
+               }
+               
+               for (i = 0; i < bb->in_count; i++) {
+                       MonoBasicBlock *in_bb = bb->in_bb [i];
+                       replace_out_block (in_bb, bb, target_bb);
+                       replace_out_block_in_code (in_bb, bb, target_bb);
+                       if (bb->in_count == 1) {
+                               replace_in_block (target_bb, bb, in_bb);
+                       } else {
+                               replace_or_add_in_block (cfg, target_bb, bb, in_bb);
+                       }
+               }
+               
+               if ((previous_bb != cfg->bb_entry) &&
+                               (previous_bb->region == bb->region) &&
+                               ((previous_bb->last_ins == NULL) ||
+                               ((previous_bb->last_ins->opcode != CEE_BR) &&
+                               (! (MONO_IS_COND_BRANCH_OP (previous_bb->last_ins))) &&
+                               (previous_bb->last_ins->opcode != CEE_SWITCH)))) {
+                       for (i = 0; i < previous_bb->out_count; i++) {
+                               if (previous_bb->out_bb [i] == target_bb) {
+                                       MonoInst *jump;
+                                       MONO_INST_NEW (cfg, jump, CEE_BR);
+                                       MONO_ADD_INS (previous_bb, jump);
+                                       jump->cil_code = previous_bb->cil_code;
+                                       jump->inst_target_bb = target_bb;
+                                       break;
+                               }
+                       }
+               }
+               
+               previous_bb->next_bb = bb->next_bb;
+               nullify_basic_block (bb);
+               
+               return TRUE;
+       } else {
+               return FALSE;
+       }
+}
 
 static void
 merge_basic_blocks (MonoBasicBlock *bb, MonoBasicBlock *bbn) 
@@ -7171,6 +7782,25 @@ merge_basic_blocks (MonoBasicBlock *bb, MonoBasicBlock *bbn)
        nullify_basic_block (bbn);
 }
 
+static void
+move_basic_block_to_end (MonoCompile *cfg, MonoBasicBlock *bb)
+{
+       MonoBasicBlock *bbn;
+
+       /* Find the previous */
+       for (bbn = cfg->bb_entry; bbn->next_bb && bbn->next_bb != bb; bbn = bbn->next_bb)
+               ;
+       if (bbn->next_bb) {
+               bbn->next_bb = bb->next_bb;
+       }
+
+       /* Find the last */
+       for (bbn = cfg->bb_entry; bbn->next_bb; bbn = bbn->next_bb)
+               ;
+       bbn->next_bb = bb;
+       bb->next_bb = NULL;
+}
+
 /*
  * Optimizes the branches on the Control Flow Graph
  *
@@ -7189,16 +7819,22 @@ optimize_branches (MonoCompile *cfg)
         */
        niterations = 1000;
        do {
+               MonoBasicBlock *previous_bb;
                changed = FALSE;
                niterations --;
 
                /* we skip the entry block (exit is handled specially instead ) */
-               for (bb = cfg->bb_entry->next_bb; bb; bb = bb->next_bb) {
+               for (previous_bb = cfg->bb_entry, bb = cfg->bb_entry->next_bb; bb; previous_bb = bb, bb = bb->next_bb) {
 
                        /* dont touch code inside exception clauses */
                        if (bb->region != -1)
                                continue;
 
+                       if (remove_block_if_useless (cfg, bb, previous_bb)) {
+                               changed = TRUE;
+                               continue;
+                       }
+
                        if ((bbn = bb->next_bb) && bbn->in_count == 0 && bb->region == bbn->region) {
                                if (cfg->verbose_level > 2)
                                        g_print ("nullify block triggered %d\n", bbn->block_num);
@@ -7217,6 +7853,13 @@ optimize_branches (MonoCompile *cfg)
 
                                /* conditional branches where true and false targets are the same can be also replaced with CEE_BR */
                                if (bb->last_ins && MONO_IS_COND_BRANCH_OP (bb->last_ins)) {
+                                       MonoInst *pop;
+                                       MONO_INST_NEW (cfg, pop, CEE_POP);
+                                       pop->inst_left = bb->last_ins->inst_left->inst_left;
+                                       mono_add_ins_to_end (bb, pop);
+                                       MONO_INST_NEW (cfg, pop, CEE_POP);
+                                       pop->inst_left = bb->last_ins->inst_left->inst_right;
+                                       mono_add_ins_to_end (bb, pop);
                                        bb->last_ins->opcode = CEE_BR;
                                        bb->last_ins->inst_target_bb = bb->last_ins->inst_true_bb;
                                        changed = TRUE;
@@ -7300,6 +7943,26 @@ optimize_branches (MonoCompile *cfg)
                                }
                        } else if (bb->out_count == 2) {
                                if (bb->last_ins && MONO_IS_COND_BRANCH_NOFP (bb->last_ins)) {
+                                       int branch_result = mono_eval_cond_branch (bb->last_ins);
+                                       MonoBasicBlock *taken_branch_target = NULL, *untaken_branch_target = NULL;
+                                       if (branch_result == BRANCH_TAKEN) {
+                                               taken_branch_target = bb->last_ins->inst_true_bb;
+                                               untaken_branch_target = bb->last_ins->inst_false_bb;
+                                       } else if (branch_result == BRANCH_NOT_TAKEN) {
+                                               taken_branch_target = bb->last_ins->inst_false_bb;
+                                               untaken_branch_target = bb->last_ins->inst_true_bb;
+                                       }
+                                       if (taken_branch_target) {
+                                               /* if mono_eval_cond_branch () is ever taken to handle 
+                                                * non-constant values to compare, issue a pop here.
+                                                */
+                                               bb->last_ins->opcode = CEE_BR;
+                                               bb->last_ins->inst_target_bb = taken_branch_target;
+                                               replace_out_block (bb, untaken_branch_target, NULL);
+                                               replace_in_block (untaken_branch_target, bb, NULL);
+                                               changed = TRUE;
+                                               break;
+                                       }
                                        bbn = bb->last_ins->inst_true_bb;
                                        if (bb->region == bbn->region && bbn->code && bbn->code->opcode == CEE_BR &&
                                            bbn->code->inst_target_bb->region == bb->region) {
@@ -7342,6 +8005,23 @@ optimize_branches (MonoCompile *cfg)
                                                break;
                                        }
                                }
+
+#ifdef MONO_ARCH_HAVE_OUT_OF_LINE_BBLOCKS
+                               if (bb->last_ins && MONO_IS_COND_BRANCH_NOFP (bb->last_ins)) {
+                                       if (bb->last_ins->inst_false_bb->out_of_line) {
+                                               /* Reverse the branch */
+                                               bb->last_ins->opcode = reverse_branch_op (bb->last_ins->opcode);
+                                               bbn = bb->last_ins->inst_false_bb;
+                                               bb->last_ins->inst_false_bb = bb->last_ins->inst_true_bb;
+                                               bb->last_ins->inst_true_bb = bbn;
+
+                                               move_basic_block_to_end (cfg, bb->last_ins->inst_true_bb);
+                                               if (cfg->verbose_level > 2)
+                                                       g_print ("cbranch to throw block triggered %d.\n", 
+                                                                        bb->block_num);
+                                       }
+                               }
+#endif
                        }
                }
        } while (changed && (niterations > 0));
@@ -7480,23 +8160,6 @@ emit_state (MonoCompile *cfg, MBState *state, int goal)
 static void 
 mini_select_instructions (MonoCompile *cfg)
 {
-       static const int reverse_map [] = {
-               CEE_BNE_UN, CEE_BLT, CEE_BLE, CEE_BGT, CEE_BGE,
-               CEE_BEQ, CEE_BLT_UN, CEE_BLE_UN, CEE_BGT_UN, CEE_BGE_UN
-       };
-       static const int reverse_fmap [] = {
-               OP_FBNE_UN, OP_FBLT, OP_FBLE, OP_FBGT, OP_FBGE,
-               OP_FBEQ, OP_FBLT_UN, OP_FBLE_UN, OP_FBGT_UN, OP_FBGE_UN
-       };
-       static const int reverse_lmap [] = {
-               OP_LBNE_UN, OP_LBLT, OP_LBLE, OP_LBGT, OP_LBGE,
-               OP_LBEQ, OP_LBLT_UN, OP_LBLE_UN, OP_LBGT_UN, OP_LBGE_UN
-       };
-       static const int reverse_imap [] = {
-               OP_IBNE_UN, OP_IBLT, OP_IBLE, OP_IBGT, OP_IBGE,
-               OP_IBEQ, OP_IBLT_UN, OP_IBLE_UN, OP_IBGT_UN, OP_IBGE_UN
-       };
-
        MonoBasicBlock *bb;
        
        cfg->state_pool = mono_mempool_new ();
@@ -7513,16 +8176,8 @@ mini_select_instructions (MonoCompile *cfg)
                                MonoBasicBlock *tmp =  bb->last_ins->inst_true_bb;
                                bb->last_ins->inst_true_bb = bb->last_ins->inst_false_bb;
                                bb->last_ins->inst_false_bb = tmp;
-                               
-                               if (bb->last_ins->opcode >= CEE_BEQ && bb->last_ins->opcode <= CEE_BLT_UN) {
-                                       bb->last_ins->opcode = reverse_map [bb->last_ins->opcode - CEE_BEQ];
-                               } else if (bb->last_ins->opcode >= OP_FBEQ && bb->last_ins->opcode <= OP_FBLT_UN) {
-                                       bb->last_ins->opcode = reverse_fmap [bb->last_ins->opcode - OP_FBEQ];
-                               } else if (bb->last_ins->opcode >= OP_LBEQ && bb->last_ins->opcode <= OP_LBLT_UN) {
-                                       bb->last_ins->opcode = reverse_lmap [bb->last_ins->opcode - OP_LBEQ];
-                               } else if (bb->last_ins->opcode >= OP_IBEQ && bb->last_ins->opcode <= OP_IBLT_UN) {
-                                       bb->last_ins->opcode = reverse_imap [bb->last_ins->opcode - OP_IBEQ];
-                               }
+
+                               bb->last_ins->opcode = reverse_branch_op (bb->last_ins->opcode);
                        } else {                        
                                MonoInst *inst = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst));
                                inst->opcode = CEE_BR;
@@ -7623,12 +8278,32 @@ mono_codegen (MonoCompile *cfg)
        for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
                bb->native_offset = cfg->code_len;
                mono_arch_output_basic_block (cfg, bb);
+
+#ifdef MONO_ARCH_HAVE_OUT_OF_LINE_BBLOCKS
+               if (bb == cfg->bb_exit) {
+                       cfg->epilog_begin = cfg->code_len;
+
+                       if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE) {
+                               code = cfg->native_code + cfg->code_len;
+                               code = mono_arch_instrument_epilog (cfg, mono_profiler_method_leave, code, FALSE);
+                               cfg->code_len = code - cfg->native_code;
+                       }
+
+                       mono_arch_emit_epilog (cfg);
+               }
+#endif
        }
+
+#ifndef MONO_ARCH_HAVE_OUT_OF_LINE_BBLOCKS
        cfg->bb_exit->native_offset = cfg->code_len;
+       max_epilog_size = mono_arch_max_epilog_size (cfg);
+#else
+       mono_arch_emit_exceptions (cfg);
 
-       code = cfg->native_code + cfg->code_len;
+       max_epilog_size = 0;
+#endif
 
-       max_epilog_size = mono_arch_max_epilog_size (cfg);
+       code = cfg->native_code + cfg->code_len;
 
        /* we always allocate code in cfg->domain->code_mp to increase locality */
        cfg->code_size = cfg->code_len + max_epilog_size;
@@ -7656,6 +8331,7 @@ mono_codegen (MonoCompile *cfg)
   
        /* g_assert (((int)cfg->native_code & (MONO_ARCH_CODE_ALIGNMENT - 1)) == 0); */
 
+#ifndef MONO_ARCH_HAVE_OUT_OF_LINE_BBLOCKS
        cfg->epilog_begin = cfg->code_len;
 
        if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
@@ -7664,6 +8340,7 @@ mono_codegen (MonoCompile *cfg)
        cfg->code_len = code - cfg->native_code;
 
        mono_arch_emit_epilog (cfg);
+#endif
 
        for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
                switch (patch_info->type) {
@@ -7702,7 +8379,7 @@ mono_codegen (MonoCompile *cfg)
                                mono_domain_unlock (cfg->domain);
                        }
 
-                       if (!mono_compile_aot)
+                       if (!cfg->compile_aot)
                                /* In the aot case, the patch already points to the correct location */
                                patch_info->ip.i = patch_info->ip.label->inst_c0;
                        for (i = 0; i < patch_info->data.table->table_size; i++) {
@@ -7925,6 +8602,7 @@ mono_local_cprop (MonoCompile *cfg)
 static void
 remove_critical_edges (MonoCompile *cfg) {
        MonoBasicBlock *bb;
+       MonoBasicBlock *previous_bb;
        
        if (cfg->verbose_level > 3) {
                for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
@@ -7946,84 +8624,82 @@ remove_critical_edges (MonoCompile *cfg) {
                }
        }
        
-       for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
-               if (bb->out_count > 1) {
-                       int out_bb_index;
-                       for (out_bb_index = 0; out_bb_index < bb->out_count; out_bb_index++) {
-                               MonoBasicBlock *out_bb = bb->out_bb [out_bb_index];
-                               if (out_bb->in_count > 1) {
-                                       MonoInst *inst;
+       for (previous_bb = cfg->bb_entry, bb = previous_bb->next_bb; bb != NULL; previous_bb = previous_bb->next_bb, bb = bb->next_bb) {
+               if (bb->in_count > 1) {
+                       int in_bb_index;
+                       for (in_bb_index = 0; in_bb_index < bb->in_count; in_bb_index++) {
+                               MonoBasicBlock *in_bb = bb->in_bb [in_bb_index];
+                               if (in_bb->out_count > 1) {
                                        MonoBasicBlock *new_bb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
                                        new_bb->block_num = cfg->num_bblocks++;
-                                       new_bb->next_bb = bb->next_bb;
-                                       bb->next_bb = new_bb;
-                                       new_bb->in_bb = mono_mempool_alloc ((cfg)->mempool, sizeof (MonoBasicBlock*));
-                                       new_bb->in_bb [0] = bb;
-                                       new_bb->in_count = 1;
-                                       new_bb->out_bb = mono_mempool_alloc ((cfg)->mempool, sizeof (MonoBasicBlock*));
-                                       new_bb->out_bb [0] = out_bb;
-                                       new_bb->out_count = 1;
-                                       replace_out_block (bb, out_bb, new_bb);
-                                       replace_in_block (out_bb, bb, new_bb);
-                                       for (inst = bb->code; inst != NULL; inst = inst->next) {
-                                               if (inst->opcode == OP_CALL_HANDLER) {
-                                                       if (inst->inst_target_bb == out_bb) {
-                                                               inst->inst_target_bb = new_bb;
-                                                       }
-                                               }
-                                       }
-                                       if (bb->last_ins != NULL) {
-                                               switch (bb->last_ins->opcode) {
-                                               case CEE_BR:
-                                                       if (bb->last_ins->inst_target_bb == out_bb) {
-                                                               bb->last_ins->inst_target_bb = new_bb;
-                                                       }
-                                                       break;
-                                               case CEE_SWITCH: {
-                                                       int i;
-                                                       int n = GPOINTER_TO_INT (bb->last_ins->klass);
-                                                       for (i = 0; i < n; i++ ) {
-                                                               if (bb->last_ins->inst_many_bb [i] == out_bb) {
-                                                                       bb->last_ins->inst_many_bb [i] = new_bb;
-                                                                       break;
+//                                     new_bb->real_offset = bb->real_offset;
+                                       new_bb->region = bb->region;
+                                       
+                                       /* Do not alter the CFG while altering the BB list */
+                                       if (previous_bb->region == bb->region) {
+                                               if (previous_bb != cfg->bb_entry) {
+                                                       /* If previous_bb "followed through" to bb, */
+                                                       /* keep it linked with a CEE_BR */
+                                                       if ((previous_bb->last_ins == NULL) ||
+                                                                       ((previous_bb->last_ins->opcode != CEE_BR) &&
+                                                                       (! (MONO_IS_COND_BRANCH_OP (previous_bb->last_ins))) &&
+                                                                       (previous_bb->last_ins->opcode != CEE_SWITCH))) {
+                                                               int i;
+                                                               /* Make sure previous_bb really falls through bb */
+                                                               for (i = 0; i < previous_bb->out_count; i++) {
+                                                                       if (previous_bb->out_bb [i] == bb) {
+                                                                               MonoInst *jump;
+                                                                               MONO_INST_NEW (cfg, jump, CEE_BR);
+                                                                               MONO_ADD_INS (previous_bb, jump);
+                                                                               jump->cil_code = previous_bb->cil_code;
+                                                                               jump->inst_target_bb = bb;
+                                                                               break;
+                                                                       }
                                                                }
                                                        }
-                                                       break;
-                                               }
-                                               case CEE_BNE_UN:
-                                               case CEE_BEQ:
-                                               case CEE_BLT:
-                                               case CEE_BLT_UN:
-                                               case CEE_BGT:
-                                               case CEE_BGT_UN:
-                                               case CEE_BGE:
-                                               case CEE_BGE_UN:
-                                               case CEE_BLE:
-                                               case CEE_BLE_UN:
-                                                       if (bb->last_ins->inst_true_bb == out_bb) {
-                                                               bb->last_ins->inst_true_bb = new_bb;
-                                                       }
-                                                       if (bb->last_ins->inst_false_bb == out_bb) {
-                                                               bb->last_ins->inst_false_bb = new_bb;
+                                               } else {
+                                                       /* We cannot add any inst to the entry BB, so we must */
+                                                       /* put a new BB in the middle to hold the CEE_BR */
+                                                       MonoInst *jump;
+                                                       MonoBasicBlock *new_bb_after_entry = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
+                                                       new_bb_after_entry->block_num = cfg->num_bblocks++;
+//                                                     new_bb_after_entry->real_offset = bb->real_offset;
+                                                       new_bb_after_entry->region = bb->region;
+                                                       
+                                                       MONO_INST_NEW (cfg, jump, CEE_BR);
+                                                       MONO_ADD_INS (new_bb_after_entry, jump);
+                                                       jump->cil_code = bb->cil_code;
+                                                       jump->inst_target_bb = bb;
+                                                       
+                                                       previous_bb->next_bb = new_bb_after_entry;
+                                                       previous_bb = new_bb_after_entry;
+                                                       
+                                                       if (cfg->verbose_level > 2) {
+                                                               printf ("remove_critical_edges %s, added helper BB%d jumping to BB%d\n", mono_method_full_name (cfg->method, TRUE), new_bb_after_entry->block_num, bb->block_num);
                                                        }
-                                                       break;
-                                               default:
-                                                       break;
                                                }
                                        }
-//                                     new_bb->real_offset = bb->real_offset;
-                                       new_bb->region = bb->region;
                                        
-                                       if (new_bb->next_bb != out_bb) {
-                                               MonoInst *jump;
-                                               MONO_INST_NEW (cfg, jump, CEE_BR);
-                                               MONO_ADD_INS (new_bb, jump);
-                                               jump->cil_code = bb->cil_code;
-                                               jump->inst_target_bb = out_bb;
-                                       }
+                                       /* Insert new_bb in the BB list */
+                                       previous_bb->next_bb = new_bb;
+                                       new_bb->next_bb = bb;
+                                       previous_bb = new_bb;
+                                       
+                                       /* Setup in_bb and out_bb */
+                                       new_bb->in_bb = mono_mempool_alloc ((cfg)->mempool, sizeof (MonoBasicBlock*));
+                                       new_bb->in_bb [0] = in_bb;
+                                       new_bb->in_count = 1;
+                                       new_bb->out_bb = mono_mempool_alloc ((cfg)->mempool, sizeof (MonoBasicBlock*));
+                                       new_bb->out_bb [0] = bb;
+                                       new_bb->out_count = 1;
+                                       
+                                       /* Relink in_bb and bb to (from) new_bb */
+                                       replace_out_block (in_bb, bb, new_bb);
+                                       replace_out_block_in_code (in_bb, bb, new_bb);
+                                       replace_in_block (bb, in_bb, new_bb);
                                        
                                        if (cfg->verbose_level > 2) {
-                                               printf ("remove_critical_edges %s, removed critical edge from BB%d to BB%d (added BB%d)\n", mono_method_full_name (cfg->method, TRUE), bb->block_num, out_bb->block_num, new_bb->block_num);
+                                               printf ("remove_critical_edges %s, removed critical edge from BB%d to BB%d (added BB%d)\n", mono_method_full_name (cfg->method, TRUE), in_bb->block_num, bb->block_num, new_bb->block_num);
                                        }
                                }
                        }
@@ -8051,9 +8727,8 @@ remove_critical_edges (MonoCompile *cfg) {
        }
 }
 
-
 MonoCompile*
-mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gboolean run_cctors, int parts)
+mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gboolean run_cctors, gboolean compile_aot, int parts)
 {
        MonoMethodHeader *header = mono_method_get_header (method);
        guint8 *ip = (guint8 *)header->code;
@@ -8074,6 +8749,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        cfg->bb_hash = g_hash_table_new (NULL, NULL);
        cfg->domain = domain;
        cfg->verbose_level = mini_verbose;
+       cfg->compile_aot = compile_aot;
        cfg->intvars = mono_mempool_alloc0 (cfg->mempool, sizeof (guint16) * STACK_MAX * 
                                            mono_method_get_header (method)->max_stack);
 
@@ -8095,7 +8771,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        mono_jit_stats.basic_blocks += cfg->num_bblocks;
        mono_jit_stats.max_basic_blocks = MAX (cfg->num_bblocks, mono_jit_stats.max_basic_blocks);
 
-       if (cfg->num_varinfo > 2000) {
+       if ((cfg->num_varinfo > 2000) && !mono_compile_aot) {
                /* 
                 * we disable some optimizations if there are too many variables
                 * because JIT time may become too expensive. The actual number needs 
@@ -8104,6 +8780,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
                cfg->opt &= ~ (MONO_OPT_LINEARS | MONO_OPT_COPYPROP | MONO_OPT_CONSPROP);
                cfg->disable_ssa = TRUE;
        }
+
        /*g_print ("numblocks = %d\n", cfg->num_bblocks);*/
 
        if (cfg->opt & MONO_OPT_BRANCH)
@@ -8207,6 +8884,28 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
 
        decompose_pass (cfg);
 
+       if (cfg->got_var) {
+               GList *regs;
+
+               /* The decompose pass may create calls which need the got var */
+               mono_emit_load_got_addr (cfg);
+
+               /* 
+                * Allways allocate the GOT var to a register, because keeping it
+                * in memory will increase the number of live temporaries in some
+                * code created by inssel.brg, leading to the well known spills+
+                * branches problem. Testcase: mcs crash in 
+                * System.MonoCustomAttrs:GetCustomAttributes.
+                */
+               regs = mono_arch_get_global_int_regs (cfg);
+               g_assert (regs);
+               cfg->got_var->opcode = OP_REGVAR;
+               cfg->got_var->dreg = GPOINTER_TO_INT (regs->data);
+               cfg->used_int_regs |= 1LL << cfg->got_var->dreg;
+               
+               g_list_free (regs);
+       }
+
        if (cfg->opt & MONO_OPT_LINEARS) {
                GList *vars, *regs;
 
@@ -8217,13 +8916,15 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
 
                if ((vars = mono_arch_get_allocatable_int_vars (cfg))) {
                        regs = mono_arch_get_global_int_regs (cfg);
+                       if (cfg->got_var)
+                               regs = g_list_delete_link (regs, regs);
                        mono_linear_scan (cfg, vars, regs, &cfg->used_int_regs);
                }
        }
 
        //mono_print_code (cfg);
 
-       //print_dfn (cfg);
+    //print_dfn (cfg);
        
        /* variables are allocated after decompose, since decompose could create temps */
        mono_arch_allocate_vars (cfg);
@@ -8255,7 +8956,6 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        if (header->num_clauses) {
                int i;
 
-               jinfo->exvar_offset = cfg->exvar? cfg->exvar->inst_offset: 0;
                jinfo->num_clauses = header->num_clauses;
                jinfo->clauses = mono_mempool_alloc0 (cfg->domain->mp, 
                        sizeof (MonoJitExceptionInfo) * header->num_clauses);
@@ -8264,9 +8964,13 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
                        MonoExceptionClause *ec = &header->clauses [i];
                        MonoJitExceptionInfo *ei = &jinfo->clauses [i];
                        MonoBasicBlock *tblock;
+                       MonoInst *exvar;
 
                        ei->flags = ec->flags;
 
+                       exvar = mono_find_exvar_for_offset (cfg, ec->handler_offset);
+                       ei->exvar_offset = exvar ? exvar->inst_offset : 0;
+
                        if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
                                tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->data.filter_offset);
                                g_assert (tblock);
@@ -8387,7 +9091,7 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain)
                return NULL;
        }
 
-       cfg = mini_method_compile (method, opt, target_domain, TRUE, 0);
+       cfg = mini_method_compile (method, opt, target_domain, TRUE, FALSE, 0);
 
        mono_domain_lock (target_domain);
 
@@ -8684,6 +9388,14 @@ SIG_HANDLER_SIGNATURE (sigusr1_signal_handler)
        mono_arch_handle_exception (ctx, exc, FALSE);
 }
 
+static void
+SIG_HANDLER_SIGNATURE (sigprof_signal_handler)
+{
+       GET_CONTEXT;
+
+       mono_profiler_stat_hit (mono_arch_ip_from_context (ctx), ctx);
+}
+
 static void
 SIG_HANDLER_SIGNATURE (sigquit_signal_handler)
 {
@@ -8769,6 +9481,89 @@ mono_runtime_install_handlers (void)
 #endif /* PLATFORM_WIN32 */
 }
 
+
+#ifdef HAVE_LINUX_RTC_H
+#include <linux/rtc.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+static int rtc_fd = -1;
+
+static int
+enable_rtc_timer (gboolean enable)
+{
+       int flags;
+       flags = fcntl (rtc_fd, F_GETFL);
+       if (flags < 0) {
+               perror ("getflags");
+               return 0;
+       }
+       if (enable)
+               flags |= FASYNC;
+       else
+               flags &= ~FASYNC;
+       if (fcntl (rtc_fd, F_SETFL, flags) == -1) {
+               perror ("setflags");
+               return 0;
+       }
+       return 1;
+}
+#endif
+
+static void
+setup_stat_profiler (void)
+{
+#ifdef ITIMER_PROF
+       struct itimerval itval;
+       static int inited = 0;
+#ifdef HAVE_LINUX_RTC_H
+       const char *rtc_freq;
+       if (!inited && (rtc_freq = g_getenv ("MONO_RTC"))) {
+               int freq = 0;
+               inited = 1;
+               if (*rtc_freq)
+                       freq = atoi (rtc_freq);
+               if (!freq)
+                       freq = 1024;
+               rtc_fd = open ("/dev/rtc", O_RDONLY);
+               if (rtc_fd == -1) {
+                       perror ("open /dev/rtc");
+                       return;
+               }
+               add_signal_handler (SIGPROF, sigprof_signal_handler);
+               if (ioctl (rtc_fd, RTC_IRQP_SET, freq) == -1) {
+                       perror ("set rtc freq");
+                       return;
+               }
+               if (ioctl (rtc_fd, RTC_PIE_ON, 0) == -1) {
+                       perror ("start rtc");
+                       return;
+               }
+               if (fcntl (rtc_fd, F_SETSIG, SIGPROF) == -1) {
+                       perror ("setsig");
+                       return;
+               }
+               if (fcntl (rtc_fd, F_SETOWN, getpid ()) == -1) {
+                       perror ("setown");
+                       return;
+               }
+               enable_rtc_timer (TRUE);
+               return;
+       }
+       if (rtc_fd >= 0)
+               return;
+#endif
+
+       itval.it_interval.tv_usec = 999;
+       itval.it_interval.tv_sec = 0;
+       itval.it_value = itval.it_interval;
+       setitimer (ITIMER_PROF, &itval, NULL);
+       if (inited)
+               return;
+       inited = 1;
+       add_signal_handler (SIGPROF, sigprof_signal_handler);
+#endif
+}
+
 /* mono_jit_create_remoting_trampoline:
  * @method: pointer to the method info
  *
@@ -8798,6 +9593,11 @@ mini_init (const char *filename)
 {
        MonoDomain *domain;
 
+       InitializeCriticalSection (&jit_mutex);
+
+       global_codeman = mono_code_manager_new ();
+       jit_icall_name_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+
        mono_arch_cpu_init ();
 
        if (!g_thread_supported ())
@@ -8808,8 +9608,6 @@ mini_init (const char *filename)
        mono_jit_tls_id = TlsAlloc ();
        setup_jit_tls_data ((gpointer)-1, mono_thread_abort);
 
-       InitializeCriticalSection (&jit_mutex);
-
        mono_burg_init ();
 
        if (default_opt & MONO_OPT_AOT)
@@ -8833,7 +9631,7 @@ mini_init (const char *filename)
        mono_install_stack_walk (mono_jit_walk_stack);
 
        domain = mono_init_from_assembly (filename, filename);
-       mono_init_icall ();
+       mono_icall_init ();
 
        mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info", 
                                ves_icall_get_frame_info);
@@ -8992,7 +9790,9 @@ print_jit_stats (void)
                g_print ("VTable data size:       %ld\n", mono_stats.class_vtable_size);
 
                g_print ("\nGeneric instances:      %ld\n", mono_stats.generic_instance_count);
-               g_print ("Inflated methods:       %ld\n", mono_stats.inflated_method_count);
+               g_print ("Initialized classes:    %ld\n", mono_stats.generic_class_count);
+               g_print ("Inflated methods:       %ld / %ld\n", mono_stats.inflated_method_count_2,
+                        mono_stats.inflated_method_count);
                g_print ("Inflated types:         %ld\n", mono_stats.inflated_type_count);
                g_print ("Generics metadata size: %ld\n", mono_stats.generics_metadata_size);
        }
@@ -9001,6 +9801,11 @@ print_jit_stats (void)
 void
 mini_cleanup (MonoDomain *domain)
 {
+#ifdef HAVE_LINUX_RTC_H
+       if (rtc_fd >= 0)
+               enable_rtc_timer (FALSE);
+#endif
+
        /* 
         * mono_runtime_cleanup() and mono_domain_finalize () need to
         * be called early since they need the execution engine still
@@ -9015,12 +9820,19 @@ mini_cleanup (MonoDomain *domain)
 
        mono_debug_cleanup ();
 
+       mono_icall_cleanup ();
+
 #ifdef PLATFORM_WIN32
        win32_seh_cleanup();
 #endif
 
        mono_domain_free (domain, TRUE);
 
+       mono_code_manager_destroy (global_codeman);
+       g_hash_table_destroy (jit_icall_name_hash);
+       if (class_init_hash_addr)
+               g_hash_table_destroy (class_init_hash_addr);
+
        print_jit_stats ();
 }