2005-01-26 Martin Baulig <martin@ximian.com>
[mono.git] / mono / mini / mini.c
index 364349f578b9f522fe114c73bca0d33875ee7fda..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);
@@ -104,6 +108,7 @@ static MonoMethodSignature *helper_sig_void_obj_ptr_ptr_obj = NULL;
 static MonoMethodSignature *helper_sig_void_ptr_ptr = NULL;
 static MonoMethodSignature *helper_sig_void_ptr_ptr_ptr = NULL;
 static MonoMethodSignature *helper_sig_ptr_ptr_ptr = NULL;
+static MonoMethodSignature *helper_sig_ptr_ptr_ptr_ptr = NULL;
 static MonoMethodSignature *helper_sig_ptr_obj = NULL;
 static MonoMethodSignature *helper_sig_ptr_obj_int = NULL;
 static MonoMethodSignature *helper_sig_ptr_int = NULL;
@@ -121,13 +126,17 @@ static MonoMethodSignature *helper_sig_int_double = NULL;
 static MonoMethodSignature *helper_sig_stelem_ref = NULL;
 static MonoMethodSignature *helper_sig_stelem_ref_check = NULL;
 static MonoMethodSignature *helper_sig_class_init_trampoline = NULL;
+static MonoMethodSignature *helper_sig_compile_generic_method = NULL;
 
 static guint32 default_opt = MONO_OPT_PEEPHOLE;
 
 guint32 mono_jit_tls_id = -1;
 MonoTraceSpec *mono_jit_trace_calls = NULL;
 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;
 
@@ -135,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)
 {
@@ -148,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)
@@ -165,14 +203,13 @@ print_method_from_ip (void *ip)
        method = mono_method_full_name (ji->method, TRUE);
        source = mono_debug_source_location_from_address (ji->method, (int) ip, NULL, domain);
 
-       g_print ("IP %p at offset 0x%x of method %s (%p %p)\n", ip, (char*)ip - (char*)ji->code_start, method, ji->code_start, (char*)ji->code_start + ji->code_size);
+       g_print ("IP %p at offset 0x%x of method %s (%p %p)[domain %p - %s]\n", ip, (int)((char*)ip - (char*)ji->code_start), method, ji->code_start, (char*)ji->code_start + ji->code_size, domain, domain->friendly_name);
 
        if (source)
                g_print ("%s\n", source);
 
        g_free (source);
        g_free (method);
-
 }
 
 G_GNUC_UNUSED void
@@ -208,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)
 {
@@ -249,7 +308,7 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
 #define CHECK_BBLOCK(target,ip,tblock) do {    \
                if ((target) < (ip) && !(tblock)->code) {       \
                        bb_recheck = g_list_prepend (bb_recheck, (tblock));     \
-                       if (cfg->verbose_level > 2) g_print ("queued block %d for check at IL%04x from IL%04x\n", (tblock)->block_num, (target) - header->code, (ip) - header->code);   \
+                       if (cfg->verbose_level > 2) g_print ("queued block %d for check at IL%04x from IL%04x\n", (tblock)->block_num, (int)((target) - header->code), (int)((ip) - header->code));     \
                }       \
        } while (0)
 
@@ -260,98 +319,95 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
                (dest)->type = STACK_I4;        \
        } while (0)
 
-#if SIZEOF_VOID_P == 8
-#define NEW_PCONST(cfg,dest,val) do {  \
-               (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
-               (dest)->opcode = OP_I8CONST;    \
-               (dest)->inst_p0 = (val);        \
-               (dest)->type = STACK_PTR;       \
-       } while (0)
-#else
 #define NEW_PCONST(cfg,dest,val) do {  \
                (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
-               (dest)->opcode = OP_ICONST;     \
+               (dest)->opcode = OP_PCONST;     \
                (dest)->inst_p0 = (val);        \
                (dest)->type = STACK_PTR;       \
        } while (0)
-#endif
 
-#if SIZEOF_VOID_P == 8
-#define OP_PCONST OP_I8CONST
-#else
-#define OP_PCONST OP_ICONST
-#endif
 
-#define NEW_CLASSCONST(cfg,dest,val) do {      \
-               (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
-               (dest)->opcode = mono_compile_aot ? OP_AOTCONST : OP_PCONST;    \
-               (dest)->inst_p0 = (val);        \
-               (dest)->inst_i1 = (gpointer)MONO_PATCH_INFO_CLASS; \
-               (dest)->type = STACK_PTR;       \
-       } while (0)
+#ifdef MONO_ARCH_NEED_GOT_VAR
 
-#define NEW_IMAGECONST(cfg,dest,val) do {      \
+#define NEW_PATCH_INFO(cfg,dest,el1,el2) do {  \
                (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
-               (dest)->opcode = mono_compile_aot ? OP_AOTCONST : OP_PCONST;    \
-               (dest)->inst_p0 = (val);        \
-               (dest)->inst_i1 = (gpointer)MONO_PATCH_INFO_IMAGE; \
-               (dest)->type = STACK_PTR;       \
+               (dest)->opcode = OP_PATCH_INFO; \
+               (dest)->inst_left = (gpointer)(el1);    \
+               (dest)->inst_right = (gpointer)(el2);   \
        } while (0)
 
-#define NEW_FIELDCONST(cfg,dest,field) do {    \
+#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)->inst_p0 = (field);      \
-               (dest)->inst_i1 = (gpointer)MONO_PATCH_INFO_FIELD; \
+               (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); \
+            (dest)->inst_p0 = got_var; \
+            (dest)->inst_p1 = group; \
+        } else { \
+                    (dest)->inst_p0 = (cons);  \
+             (dest)->inst_i1 = (gpointer)(patch_type); \
+        } \
                (dest)->type = STACK_PTR;       \
-       } while (0)
+    } while (0)
 
-#define NEW_METHODCONST(cfg,dest,val) do {     \
+#define NEW_AOTCONST_TOKEN(cfg,dest,patch_type,image,token,stack_type) do { \
+        MonoInst *group, *got_var; \
                (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
-               (dest)->opcode = mono_compile_aot ? OP_AOTCONST : OP_PCONST;    \
-               (dest)->inst_p0 = (val);        \
-               (dest)->inst_i1 = (gpointer)MONO_PATCH_INFO_METHODCONST; \
-               (dest)->type = STACK_PTR;       \
-       } while (0)
+               (dest)->opcode = OP_GOT_ENTRY;  \
+        NEW_TEMPLOAD ((cfg), got_var, mono_get_got_var (cfg)->inst_c0); \
+               NEW_PATCH_INFO ((cfg), group, NULL, patch_type); \
+        group->inst_p0 = mono_jump_info_token_new ((cfg)->mempool, (image), (token)); \
+        (dest)->inst_p0 = got_var; \
+        (dest)->inst_p1 = group; \
+               (dest)->type = (stack_type);    \
+    } while (0)
 
-#define NEW_VTABLECONST(cfg,dest,vtable) do {  \
-               (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
-               (dest)->opcode = mono_compile_aot ? OP_AOTCONST : OP_PCONST;    \
-               (dest)->inst_p0 = mono_compile_aot ? (gpointer)((vtable)->klass) : (vtable);    \
-               (dest)->inst_i1 = (gpointer)MONO_PATCH_INFO_VTABLE; \
-               (dest)->type = STACK_PTR;       \
-       } while (0)
+#else
 
-#define NEW_SFLDACONST(cfg,dest,field) do {    \
+#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)->inst_p0 = (field);      \
-               (dest)->inst_i1 = (gpointer)MONO_PATCH_INFO_SFLDA; \
+               (dest)->opcode = cfg->compile_aot ? OP_AOTCONST : OP_PCONST;    \
+               (dest)->inst_p0 = (cons);       \
+               (dest)->inst_i1 = (gpointer)(patch_type); \
                (dest)->type = STACK_PTR;       \
-       } while (0)
+    } while (0)
 
-#define NEW_LDSTRCONST(cfg,dest,image,token) do {      \
+#define NEW_AOTCONST_TOKEN(cfg,dest,patch_type,image,token,stack_type) do {    \
                (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
                (dest)->opcode = OP_AOTCONST;   \
                (dest)->inst_p0 = mono_jump_info_token_new ((cfg)->mempool, (image), (token));  \
-               (dest)->inst_i1 = (gpointer)MONO_PATCH_INFO_LDSTR; \
-               (dest)->type = STACK_OBJ;       \
-       } while (0)
+               (dest)->inst_p1 = (gpointer)(patch_type); \
+               (dest)->type = (stack_type);    \
+    } while (0)
 
-#define NEW_TYPE_FROM_HANDLE_CONST(cfg,dest,image,token) do {  \
-               (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
-               (dest)->opcode = OP_AOTCONST;   \
-               (dest)->inst_p0 = mono_jump_info_token_new ((cfg)->mempool, (image), (token));  \
-               (dest)->inst_i1 = (gpointer)MONO_PATCH_INFO_TYPE_FROM_HANDLE; \
-               (dest)->type = STACK_OBJ;       \
-       } while (0)
+#endif
 
-#define NEW_LDTOKENCONST(cfg,dest,image,token) do {    \
-               (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
-               (dest)->opcode = OP_AOTCONST;   \
-               (dest)->inst_p0 = mono_jump_info_token_new ((cfg)->mempool, (image), (token));  \
-               (dest)->inst_i1 = (gpointer)MONO_PATCH_INFO_LDTOKEN; \
-               (dest)->type = STACK_PTR;       \
+#define NEW_CLASSCONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_CLASS, (val))
+
+#define NEW_IMAGECONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_IMAGE, (val))
+
+#define NEW_FIELDCONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_FIELD, (val))
+
+#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, cfg->compile_aot ? (gpointer)((vtable)->klass) : (vtable))
+
+#define NEW_SFLDACONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_SFLDA, (val))
+
+#define NEW_LDSTRCONST(cfg,dest,image,token) NEW_AOTCONST_TOKEN ((cfg), (dest), MONO_PATCH_INFO_LDSTR, (image), (token), STACK_OBJ)
+
+#define NEW_TYPE_FROM_HANDLE_CONST(cfg,dest,image,token) NEW_AOTCONST_TOKEN ((cfg), (dest), MONO_PATCH_INFO_TYPE_FROM_HANDLE, (image), (token), STACK_OBJ)
+
+#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 { \
@@ -484,6 +540,19 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
                (dest)->klass = (dest)->inst_i0->klass; \
        } while (0)
 
+#define NEW_DUMMY_USE(cfg,dest,load) do { \
+               (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
+               (dest)->opcode = OP_DUMMY_USE; \
+               (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;     \
@@ -673,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);
@@ -684,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)) {
@@ -751,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)
 {
@@ -847,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)
 {
@@ -896,7 +1023,7 @@ handle_enum:
        case MONO_TYPE_TYPEDBYREF:
                return CEE_LDOBJ;
        case MONO_TYPE_GENERICINST:
-               type = type->data.generic_inst->generic_type;
+               type = &type->data.generic_class->container_class->byval_arg;
                goto handle_enum;
        default:
                g_error ("unknown type 0x%02x in type_to_ldind", type->type);
@@ -950,7 +1077,7 @@ handle_enum:
        case MONO_TYPE_TYPEDBYREF:
                return CEE_STOBJ;
        case MONO_TYPE_GENERICINST:
-               type = type->data.generic_inst->generic_type;
+               type = &type->data.generic_class->container_class->byval_arg;
                goto handle_enum;
        default:
                g_error ("unknown type 0x%02x in type_to_stind", type->type);
@@ -963,14 +1090,22 @@ handle_enum:
  * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
  */
 static void
-type_to_eval_stack_type (MonoType *type, MonoInst *inst) {
+type_to_eval_stack_type (MonoType *type, MonoInst *inst)
+{
+       MonoClass *klass;
+
        if (type->byref) {
                inst->type = STACK_MP;
                return;
        }
 
+       klass = mono_class_from_mono_type (type);
+
 handle_enum:
        switch (type->type) {
+       case MONO_TYPE_VOID:
+               inst->type = STACK_INV;
+               return;
        case MONO_TYPE_I1:
        case MONO_TYPE_U1:
        case MONO_TYPE_BOOLEAN:
@@ -1007,7 +1142,7 @@ handle_enum:
                        type = type->data.klass->enum_basetype;
                        goto handle_enum;
                } else {
-                       inst->klass = type->data.klass;
+                       inst->klass = klass;
                        inst->type = STACK_VTYPE;
                        return;
                }
@@ -1016,7 +1151,7 @@ handle_enum:
                inst->type = STACK_VTYPE;
                return;
        case MONO_TYPE_GENERICINST:
-               type = type->data.generic_inst->generic_type;
+               type = &type->data.generic_class->container_class->byval_arg;
                goto handle_enum;
        default:
                g_error ("unknown type 0x%02x in eval stack type", type->type);
@@ -1398,6 +1533,25 @@ mono_get_domainvar (MonoCompile *cfg)
        return cfg->domainvar;
 }
 
+/*
+ * The got_var contains the address of the Global Offset Table when AOT 
+ * compiling.
+ */
+inline static MonoInst *
+mono_get_got_var (MonoCompile *cfg)
+{
+#ifdef MONO_ARCH_NEED_GOT_VAR
+       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);
+       }
+       return cfg->got_var;
+#else
+       return NULL;
+#endif
+}
+
 MonoInst*
 mono_compile_create_var (MonoCompile *cfg, MonoType *type, int opcode)
 {
@@ -1430,6 +1584,39 @@ mono_compile_create_var (MonoCompile *cfg, MonoType *type, int opcode)
        return inst;
 }
 
+/*
+ * Transform a MonoInst into a load from the variable of index var_index.
+ */
+void
+mono_compile_make_var_load (MonoCompile *cfg, MonoInst *dest, gssize var_index) {
+       memset (dest, 0, sizeof (MonoInst));
+       dest->ssa_op = MONO_SSA_LOAD;
+       dest->inst_i0 = cfg->varinfo [var_index];
+       dest->opcode = mono_type_to_ldind (dest->inst_i0->inst_vtype);
+       type_to_eval_stack_type (dest->inst_i0->inst_vtype, dest);
+       dest->klass = dest->inst_i0->klass;
+}
+
+/*
+ * Create a MonoInst that is a load from the variable of index var_index.
+ */
+MonoInst*
+mono_compile_create_var_load (MonoCompile *cfg, gssize var_index) {
+       MonoInst *dest;
+       NEW_TEMPLOAD (cfg,dest,var_index);
+       return dest;
+}
+
+/*
+ * Create a MonoInst that is a store of the given value into the variable of index var_index.
+ */
+MonoInst*
+mono_compile_create_var_store (MonoCompile *cfg, gssize var_index, MonoInst *value) {
+       MonoInst *dest;
+       NEW_TEMPSTORE (cfg, dest, var_index, value);
+       return dest;
+}
+
 static MonoType*
 type_from_stack_type (MonoInst *ins) {
        switch (ins->type) {
@@ -1446,6 +1633,11 @@ type_from_stack_type (MonoInst *ins) {
        return NULL;
 }
 
+MonoType*
+mono_type_from_stack_type (MonoInst *ins) {
+       return type_from_stack_type (ins);
+}
+
 static MonoClass*
 array_access_to_klass (int opcode)
 {
@@ -1486,7 +1678,7 @@ array_access_to_klass (int opcode)
        return NULL;
 }
 
-static void
+void
 mono_add_ins_to_end (MonoBasicBlock *bb, MonoInst *inst)
 {
        MonoInst *prev;
@@ -1659,7 +1851,7 @@ handle_stack_args (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **sp, int coun
                        mono_add_ins_to_end (bb, inst);
                }
                if (cfg->verbose_level > 3)
-                       g_print ("storing %d to temp %d\n", i, locals [i]->inst_c0);
+                       g_print ("storing %d to temp %d\n", i, (int)locals [i]->inst_c0);
        }
 
        /*
@@ -1738,7 +1930,7 @@ handle_enum:
        case MONO_TYPE_TYPEDBYREF:
                return calli? OP_VCALL_REG: virt? OP_VCALLVIRT: OP_VCALL;
        case MONO_TYPE_GENERICINST:
-               type = type->data.generic_inst->generic_type;
+               type = &type->data.generic_class->container_class->byval_arg;
                goto handle_enum;
        default:
                g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
@@ -1750,12 +1942,16 @@ void
 mono_create_jump_table (MonoCompile *cfg, MonoInst *label, MonoBasicBlock **bbs, int num_blocks)
 {
        MonoJumpInfo *ji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
+       MonoJumpInfoBBTable *table;
+
+       table = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
+       table->table = bbs;
+       table->table_size = num_blocks;
        
        ji->ip.label = label;
        ji->type = MONO_PATCH_INFO_SWITCH;
-       ji->data.table = bbs;
+       ji->data.table = table;
        ji->next = cfg->patch_info;
-       ji->table_size = num_blocks;
        cfg->patch_info = ji;
 }
 
@@ -1775,8 +1971,11 @@ handle_loaded_temps (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst **stack,
        while (stack < sp) {
                ins = *stack;
                /* handle also other constants */
-               if (ins->opcode != OP_ICONST) {
+               if ((ins->opcode != OP_ICONST) &&
+                   /* temps never get written to again, so we can safely avoid duplicating them */
+                   !(ins->ssa_op == MONO_SSA_LOAD && ins->inst_i0->opcode == OP_LOCAL && ins->inst_i0->flags & MONO_INST_IS_TEMP)) {
                        temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
+                       temp->flags |= MONO_INST_IS_TEMP;
                        NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
                        store->cil_code = ins->cil_code;
                        if (store->opcode == CEE_STOBJ) {
@@ -1812,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;
@@ -1889,7 +2069,7 @@ handle_enum:
                                return 1;
                        continue;
                case MONO_TYPE_GENERICINST:
-                       simple_type = simple_type->data.generic_inst->generic_type;
+                       simple_type = &simple_type->data.generic_class->container_class->byval_arg;
                        goto handle_enum;
 
                default:
@@ -1916,9 +2096,21 @@ mono_spill_call (MonoCompile *cfg, MonoBasicBlock *bblock, MonoCallInst *call, M
                        type_to_eval_stack_type (ret, ins);
                        temp = mono_compile_create_var (cfg, ret, OP_LOCAL);
                }
+               
+               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;
@@ -1964,7 +2156,8 @@ mono_emit_call_args (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignatu
        call->args = args;
        call->signature = sig;
        call = mono_arch_call_opcode (cfg, bblock, call, virtual);
-
+       type_to_eval_stack_type (sig->ret, &call->inst);
+       
        for (arg = call->out_args; arg;) {
                MonoInst *narg = arg->next;
                arg->next = NULL;
@@ -2009,6 +2202,12 @@ mono_emit_method_call (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *met
        call->inst.flags |= MONO_INST_HAS_METHOD;
        call->inst.inst_left = this;
 
+       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);
+
        return call;
 }
 
@@ -2044,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);
 }
 
@@ -2066,8 +2266,11 @@ 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;
                NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
                store->cil_code = tree->cil_code;
        } else {
@@ -2118,7 +2321,7 @@ mono_get_element_address_signature (int arity)
        if (!sighash) {
                sighash = g_hash_table_new (NULL, NULL);
        }
-       else if ((res = g_hash_table_lookup (sighash, (gpointer)arity))) {
+       else if ((res = g_hash_table_lookup (sighash, GINT_TO_POINTER (arity)))) {
                LeaveCriticalSection (&jit_mutex);
                return res;
        }
@@ -2137,7 +2340,7 @@ mono_get_element_address_signature (int arity)
 
        res->ret = &mono_defaults.int_class->byval_arg;
 
-       g_hash_table_insert (sighash, (gpointer)arity, res);
+       g_hash_table_insert (sighash, GINT_TO_POINTER (arity), res);
        LeaveCriticalSection (&jit_mutex);
 
        return res;
@@ -2154,7 +2357,7 @@ mono_get_array_new_va_signature (int arity)
        if (!sighash) {
                sighash = g_hash_table_new (NULL, NULL);
        }
-       else if ((res = g_hash_table_lookup (sighash, (gpointer)arity))) {
+       else if ((res = g_hash_table_lookup (sighash, GINT_TO_POINTER (arity)))) {
                LeaveCriticalSection (&jit_mutex);
                return res;
        }
@@ -2173,7 +2376,7 @@ mono_get_array_new_va_signature (int arity)
 
        res->ret = &mono_defaults.int_class->byval_arg;
 
-       g_hash_table_insert (sighash, (gpointer)arity, res);
+       g_hash_table_insert (sighash, GINT_TO_POINTER (arity), res);
        LeaveCriticalSection (&jit_mutex);
 
        return res;
@@ -2198,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;
@@ -2321,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 */
@@ -2329,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;
@@ -2337,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
@@ -2422,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);
@@ -2444,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);
@@ -2466,10 +2719,9 @@ mono_find_jit_opcode_emulation (int opcode)
 }
 
 static MonoInst*
-mini_get_opcode_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
+mini_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
 {
-       int pc, op;
-       MonoInst *ins;
+       MonoInst *ins = NULL;
        
        static MonoClass *runtime_helpers_class = NULL;
        if (! runtime_helpers_class)
@@ -2480,22 +2732,41 @@ mini_get_opcode_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSig
                if (cmethod->name [0] != 'g')
                        return NULL;
  
-               if (strcmp (cmethod->name, "get_Chars") == 0)
-                       op = OP_GETCHR;
-               else if (strcmp (cmethod->name, "get_Length") == 0)
-                       op = OP_STRLEN;
-               else return NULL;
+               if (strcmp (cmethod->name, "get_Chars") == 0) {
+                       MONO_INST_NEW (cfg, ins, OP_GETCHR);
+                       ins->inst_i0 = args [0];
+                       ins->inst_i1 = args [1];
+                       return ins;
+               } else if (strcmp (cmethod->name, "get_Length") == 0) {
+                       MONO_INST_NEW (cfg, ins, OP_STRLEN);
+                       ins->inst_i0 = args [0];
+                       return ins;
+               } else 
+                       return NULL;
        } else if (cmethod->klass == mono_defaults.object_class) {
-               if (strcmp (cmethod->name, "GetType") == 0)
-                       op = OP_GETTYPE;
-               else
+               if (strcmp (cmethod->name, "GetType") == 0) {
+                       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) {
-               if (strcmp (cmethod->name, "get_Rank") == 0)
-                       op = OP_ARRAY_RANK;
-               else if (strcmp (cmethod->name, "get_Length") == 0)
-                       op = CEE_LDLEN;
-               else
+               if (cmethod->name [0] != 'g')
+                       return NULL;
+
+               if (strcmp (cmethod->name, "get_Rank") == 0) {
+                       MONO_INST_NEW (cfg, ins, OP_ARRAY_RANK);
+                       ins->inst_i0 = args [0];
+                       return ins;
+               } else if (strcmp (cmethod->name, "get_Length") == 0) {
+                       MONO_INST_NEW (cfg, ins, CEE_LDLEN);
+                       ins->inst_i0 = args [0];
+                       return ins;
+               } else
                        return NULL;
        } else if (cmethod->klass == runtime_helpers_class) {
                if (strcmp (cmethod->name, "get_OffsetToStringData") == 0) {
@@ -2507,21 +2778,9 @@ mini_get_opcode_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSig
                if (strcmp (cmethod->name, "get_CurrentThread") == 0 && (ins = mono_arch_get_thread_intrinsic (cfg)))
                        return ins;
                return NULL;
-       } else {
-               op = mono_arch_get_opcode_for_method (cfg, cmethod, fsig, args);
-               if (op < 0)
-                       return NULL;
-       }
-       pc = fsig->param_count + fsig->hasthis;
-       MONO_INST_NEW (cfg, ins, op);
-
-       if (pc > 0) {
-               ins->inst_i0 = args [0];
-               if (pc > 1)
-                       ins->inst_i1 = args [1];
        }
 
-       return ins;
+       return mono_arch_get_inst_for_method (cfg, cmethod, fsig, args);
 }
 
 static void
@@ -2675,6 +2934,14 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig,
 /* offset from br.s -> br like opcodes */
 #define BIG_BRANCH_OFFSET 13
 
+static gboolean
+ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
+{
+       MonoBasicBlock *b = g_hash_table_lookup (cfg->bb_hash, ip);
+       
+       return b == NULL || b == bb;
+}
+
 static int
 get_basic_blocks (MonoCompile *cfg, GHashTable *bbhash, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
 {
@@ -2752,10 +3019,17 @@ unverified:
 }
 
 static MonoInst*
-emit_tree (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ins)
+emit_tree (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ins, const guint8* ip_next)
 {
        MonoInst *store, *temp, *load;
+       
+       if (ip_in_bb (cfg, bblock, ip_next) &&
+               (CODE_IS_STLOC (ip_next) || *ip_next == CEE_BRTRUE || *ip_next == CEE_BRFALSE ||
+               *ip_next == CEE_BRTRUE_S || *ip_next == CEE_BRFALSE_S || *ip_next == CEE_RET))
+                       return ins;
+       
        temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
+       temp->flags |= MONO_INST_IS_TEMP;
        NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
        store->cil_code = ins->cil_code;
        MONO_ADD_INS (bblock, store);
@@ -2764,6 +3038,17 @@ emit_tree (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ins)
        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
  */
@@ -2792,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);
@@ -2808,7 +3094,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
        if (method->signature->is_inflated)
                generic_context = ((MonoMethodInflated *) method)->context;
        else if (generic_container)
-               generic_context = generic_container->context;
+               generic_context = &generic_container->context;
+
+       g_assert (!method->signature->has_type_parameters);
 
        if (cfg->method == method) {
                real_offset = 0;
@@ -2824,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);
 
@@ -2845,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) {
@@ -2873,29 +3162,33 @@ 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);
                                }
                        }
                }
-
        } else {
                arg_array = alloca (sizeof (MonoInst *) * num_args);
                mono_save_args (cfg, start_bblock, sig, inline_args, arg_array);
@@ -2914,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;
@@ -2929,12 +3231,42 @@ 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;
        }
 
-       mono_debug_init_method (cfg, bblock, breakpoint_id);
+       if (cfg->method == method)
+               mono_debug_init_method (cfg, bblock, breakpoint_id);
 
        param_types = mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
        if (sig->hasthis)
@@ -2986,7 +3318,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        start_new_bblock = 0;
                        for (i = 0; i < bblock->in_scount; ++i) {
                                if (cfg->verbose_level > 3)
-                                       g_print ("loading %d from temp %d\n", i, bblock->in_stack [i]->inst_c0);                                                
+                                       g_print ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);                                           
                                NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
                                *sp++ = ins;
                        }
@@ -3001,7 +3333,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                bblock = tblock;
                                for (i = 0; i < bblock->in_scount; ++i) {
                                        if (cfg->verbose_level > 3)
-                                               g_print ("loading %d from temp %d\n", i, bblock->in_stack [i]->inst_c0);                                                
+                                               g_print ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);                                           
                                        NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
                                        *sp++ = ins;
                                }
@@ -3031,7 +3363,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                }
 
                if (cfg->verbose_level > 3)
-                       g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, sp-stack_start, mono_disasm_code_one (NULL, method, ip, NULL));
+                       g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
 
                switch (*ip) {
                case CEE_NOP:
@@ -3217,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;
@@ -3230,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;
@@ -3253,17 +3587,60 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                temp->cil_code = ip;
                                *sp++ = temp;
                        } else {
-                               temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
-                               temp->cil_code = ip;
-                               NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
-                               store->cil_code = ip;
-                               MONO_ADD_INS (bblock, store);
-                               NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
-                               *sp++ = ins;
-                               ins->cil_code = ip;
-                               NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
-                               *sp++ = ins;
-                               ins->cil_code = ip;
+                               /* Common idiom: ... / dup / stloc.x */
+                               int ins_len = 0;
+                               if (ip_in_bb (cfg, bblock, ip + 1)) {
+                                       switch (ip [1]) {
+                                       case CEE_STLOC_0:
+                                       case CEE_STLOC_1:
+                                       case CEE_STLOC_2:
+                                       case CEE_STLOC_3:
+                                               n = (ip [1]) - CEE_STLOC_0;
+                                               ins_len = 1;
+                                               break;
+                                       
+                                       case CEE_STLOC_S:
+                                               n = ip [2];
+                                               ins_len = 2;
+                                               break;
+                                       
+                                       case CEE_PREFIX1:
+                                               if (ip [2] == CEE_LDLOC) {
+                                                       n = read16 (ip + 3);
+                                                       ins_len = 4;
+                                               }
+                                       }
+                               }
+                               
+                               if (ins_len) {
+                                       CHECK_LOCAL (n);
+                                       handle_loaded_temps (cfg, bblock, stack_start, sp - 1);
+                                       NEW_LOCSTORE (cfg, ins, n, *sp);
+                                       ins->cil_code = ip;
+                                       if (ins->opcode == CEE_STOBJ) {
+                                               NEW_LOCLOADA (cfg, ins, n);
+                                               handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
+                                       } else
+                                               MONO_ADD_INS (bblock, ins);
+                                       
+                                       NEW_LOCLOAD (cfg, *sp, n);
+                                       (*sp)->cil_code = ip;
+                                       ip += ins_len;
+                                       sp++;
+                               } else {
+                                       temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
+                                       temp->flags |= MONO_INST_IS_TEMP;
+                                       temp->cil_code = ip;
+                                       NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
+                                       store->cil_code = ip;
+                                       MONO_ADD_INS (bblock, store);
+                                       NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
+                                       *sp++ = ins;
+                                       ins->cil_code = ip;
+                                       NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
+                                       *sp++ = ins;
+                                       ins->cil_code = ip;
+                               }
                        }
                        ++ip;
                        inline_costs += 2;
@@ -3284,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;
@@ -3317,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);
@@ -3327,10 +3705,12 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        mono_class_init (cmethod->klass);
 
                                if (cmethod->signature->pinvoke) {
-                                               MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod);
-                                               fsig = wrapper->signature;
+                                       MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod);
+                                       fsig = wrapper->signature;
+                               } else if (constrained_call) {
+                                       fsig = cmethod->signature;
                                } else {
-                                       fsig = mono_method_get_signature (cmethod, image, token);
+                                       fsig = mono_method_get_signature_full (cmethod, image, token, generic_context);
                                }
 
                                n = fsig->param_count + fsig->hasthis;
@@ -3345,6 +3725,21 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                        }
 
+                       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);
 
                        //g_assert (!virtual || fsig->hasthis);
@@ -3388,8 +3783,40 @@ 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;
+                               MonoInst *iargs [3];
+
+                               g_assert (cmethod->signature->is_inflated);
+
+                               this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
+                               this_temp->cil_code = ip;
+                               NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
+
+                               store->cil_code = ip;
+                               MONO_ADD_INS (bblock, store);
+
+                               NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
+                               NEW_PCONST (cfg, iargs [1], cmethod);
+                               NEW_PCONST (cfg, iargs [2], ((MonoMethodInflated *) cmethod)->context);
+                               temp = mono_emit_jit_icall (cfg, bblock, helper_compile_generic_method, iargs, ip);
+
+                               NEW_TEMPLOAD (cfg, addr, temp);
+                               NEW_TEMPLOAD (cfg, sp [0], this_temp->inst_c0);
+
+                               if ((temp = mono_emit_calli (cfg, bblock, fsig, sp, addr, ip)) != -1) {
+                                       NEW_TEMPLOAD (cfg, *sp, temp);
+                                       sp++;
+                               }
+
+                               ip += 5;
+                               break;
+                       }
 
                        if ((ins_flag & MONO_INST_TAILCALL) && cmethod && (*ip == CEE_CALL) && (mono_metadata_signature_equal (method->signature, cmethod->signature))) {
                                int i;
@@ -3416,13 +3843,14 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                ins->inst_p0 = cmethod;
                                ins->inst_p1 = arg_array [0];
                                MONO_ADD_INS (bblock, ins);
+                               link_bblock (cfg, bblock, end_bblock);                  
                                start_new_bblock = 1;
                                /* skip CEE_RET as well */
                                ip += 6;
                                ins_flag = 0;
                                break;
                        }
-                       if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_get_opcode_for_method (cfg, cmethod, fsig, sp))) {
+                       if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_get_inst_for_method (cfg, cmethod, fsig, sp))) {
                                ins->cil_code = ip;
 
                                if (MONO_TYPE_IS_VOID (fsig->ret)) {
@@ -3576,7 +4004,11 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                }
 
                        } else {
-                               if (0 && CODE_IS_STLOC (ip + 5) && (!MONO_TYPE_ISSTRUCT (fsig->ret)) && (!MONO_TYPE_IS_VOID (fsig->ret) || cmethod->string_ctor)) {
+                               if (ip_in_bb (cfg, bblock, ip + 5) 
+                                   && (!MONO_TYPE_ISSTRUCT (fsig->ret))
+                                   && (!MONO_TYPE_IS_VOID (fsig->ret) || cmethod->string_ctor)
+                                   && (CODE_IS_STLOC (ip + 5) || ip [5] == CEE_POP || ip [5] == CEE_BRTRUE || ip [5] == CEE_BRFALSE ||
+                                       ip [5] == CEE_BRTRUE_S || ip [5] == CEE_BRFALSE_S || ip [5] == CEE_RET)) {
                                        /* no need to spill */
                                        ins = (MonoInst*)mono_emit_method_call (cfg, bblock, cmethod, fsig, sp, ip, virtual ? sp [0] : NULL);
                                        *sp++ = ins;
@@ -3777,6 +4209,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
                                sp = stack_start;
                        }
+                       /* Needed by the code generated in inssel.brg */
+                       mono_get_got_var (cfg);
                        inline_costs += 20;
                        break;
                case CEE_LDIND_I1:
@@ -3848,7 +4282,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        }
                        if (mono_find_jit_opcode_emulation (ins->opcode)) {
                                --sp;
-                               *sp++ = emit_tree (cfg, bblock, ins);
+                               *sp++ = emit_tree (cfg, bblock, ins, ip + 1);
                        }
                        ip++;
                        break;
@@ -3869,7 +4303,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        ADD_UNOP (*ip);
                        if (mono_find_jit_opcode_emulation (ins->opcode)) {
                                --sp;
-                               *sp++ = emit_tree (cfg, bblock, ins);
+                               *sp++ = emit_tree (cfg, bblock, ins, ip + 1);
                        }
                        ip++;                   
                        break;
@@ -3933,7 +4367,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                MONO_INST_NEW (cfg, load, CEE_LDIND_REF);
                                load->cil_code = ip;
                                load->inst_i0 = sp [1];
-                               load->type = ldind_type [CEE_LDIND_REF];
+                               load->type = STACK_OBJ;
                                load->flags |= ins_flag;
                                MONO_INST_NEW (cfg, store, CEE_STIND_REF);
                                store->cil_code = ip;
@@ -3967,6 +4401,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        break;
                case CEE_LDOBJ: {
                        MonoInst *iargs [3];
+                       int loc_index = -1;
+                       int stloc_len = 0;
                        CHECK_OPSIZE (5);
                        CHECK_STACK (1);
                        --sp;
@@ -3981,13 +4417,47 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                MONO_INST_NEW (cfg, ins, CEE_LDIND_REF);
                                ins->cil_code = ip;
                                ins->inst_i0 = sp [0];
-                               ins->type = ldind_type [CEE_LDIND_REF];
+                               ins->type = STACK_OBJ;
                                ins->flags |= ins_flag;
                                ins_flag = 0;
                                *sp++ = ins;
                                ip += 5;
                                break;
                        }
+
+                       /* Optimize the common ldobj+stloc combination */
+                       switch (ip [5]) {
+                       case CEE_STLOC_S:
+                               loc_index = ip [6];
+                               stloc_len = 2;
+                               break;
+                       case CEE_STLOC_0:
+                       case CEE_STLOC_1:
+                       case CEE_STLOC_2:
+                       case CEE_STLOC_3:
+                               loc_index = ip [5] - CEE_STLOC_0;
+                               stloc_len = 1;
+                               break;
+                       default:
+                               break;
+                       }
+
+                       if ((loc_index != -1) && ip_in_bb (cfg, bblock, ip + 5)) {
+                               CHECK_LOCAL (loc_index);
+                               NEW_LOCSTORE (cfg, ins, loc_index, *sp);
+
+                               if (ins->opcode == CEE_STOBJ) {
+                                       handle_loaded_temps (cfg, bblock, stack_start, sp);
+                                       ins->cil_code = ip;
+                                       g_assert (ins->opcode == CEE_STOBJ);
+                                       NEW_LOCLOADA (cfg, ins, loc_index);
+                                       handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
+                                       ip += 5;
+                                       ip += stloc_len;
+                                       break;
+                               }
+                       }
+
                        n = mono_class_value_size (klass, NULL);
                        ins = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
                        NEW_TEMPLOADA (cfg, iargs [0], ins->inst_c0);
@@ -4038,8 +4508,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        int temp;
                                        MonoInst *iargs [3];
 
-                                       if (mono_compile_aot) {
-                                               cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, (gpointer)n);
+                                       if (cfg->compile_aot) {
+                                               cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
                                        }
 
                                        NEW_TEMPLOAD (cfg, iargs [0], mono_get_domainvar (cfg)->inst_c0);
@@ -4049,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);
@@ -4074,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);
@@ -4160,7 +4630,10 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        else
                                klass = mono_class_get_full (image, token, generic_context);
                        mono_class_init (klass);
-               
+
+                       /* Needed by the code generated in inssel.brg */
+                       mono_get_got_var (cfg);
+
                        if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
                        
                                MonoMethod *mono_isinst;
@@ -4198,7 +4671,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                ins->inst_left = *sp;
                                ins->inst_newa_class = klass;
                                ins->cil_code = ip;
-                               *sp++ = emit_tree (cfg, bblock, ins);
+                               *sp++ = emit_tree (cfg, bblock, ins, ip + 5);
                                ip += 5;
                        }
                        break;
@@ -4255,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;
                        }
 
@@ -4311,6 +4784,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                klass = mono_class_get_full (image, token, generic_context);
                        mono_class_init (klass);
 
+                       /* Needed by the code generated in inssel.brg */
+                       mono_get_got_var (cfg);
+
                        MONO_INST_NEW (cfg, ins, OP_UNBOXCAST);
                        ins->type = STACK_OBJ;
                        ins->inst_left = *sp;
@@ -4338,6 +4814,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        else
                                klass = mono_class_get_full (image, token, generic_context);
                        mono_class_init (klass);
+
+                       /* Needed by the code generated in inssel.brg */
+                       mono_get_got_var (cfg);
                
                        if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
                                
@@ -4376,7 +4855,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                ins->klass = klass;
                                ins->inst_newa_class = klass;
                                ins->cil_code = ip;
-                               *sp++ = emit_tree (cfg, bblock, ins);
+                               *sp++ = emit_tree (cfg, bblock, ins, ip + 5);
                                ip += 5;
                        }
                        break;
@@ -4386,8 +4865,10 @@ 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);
                        start_new_bblock = 1;
                        break;
                case CEE_LDFLD:
@@ -4482,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);
@@ -4560,10 +5041,16 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if ((*ip) == CEE_STSFLD)
                                handle_loaded_temps (cfg, bblock, stack_start, sp);
 
+                       /* The special_static_fields field is init'd in mono_class_vtable, so it needs
+                        * to be called here.
+                        */
+                       if (!(cfg->opt & MONO_OPT_SHARED))
+                               mono_class_vtable (cfg->domain, klass);
+                       
                        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);
@@ -4575,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,
@@ -4588,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);
@@ -4628,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));
@@ -4772,7 +5263,10 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                /* LAME-IR: Mark it as used since otherwise it will be optimized away */
                                cfg->domainvar->flags |= MONO_INST_VOLATILE;
                        }
-                       
+
+                       /* Ditto */
+                       mono_get_got_var (cfg);
+
                        if (method->wrapper_type != MONO_WRAPPER_NONE)
                                klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
                        else
@@ -4819,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;
@@ -5050,12 +5559,13 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                        if (cfg->opt & MONO_OPT_SHARED) {
                                int temp;
-                               MonoInst *res, *store, *addr, *vtvar, *iargs [2];
+                               MonoInst *res, *store, *addr, *vtvar, *iargs [3];
 
                                vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
 
                                NEW_IMAGECONST (cfg, iargs [0], image);
                                NEW_ICONST (cfg, iargs [1], n);
+                               NEW_PCONST (cfg, iargs [2], generic_context);
                                temp = mono_emit_jit_icall (cfg, bblock, mono_ldtoken_wrapper, iargs, ip);
                                NEW_TEMPLOAD (cfg, res, temp);
                                NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
@@ -5063,14 +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) && 
-                                       ((g_hash_table_lookup (bbhash, ip + 5) == NULL) ||
-                                        (g_hash_table_lookup (bbhash, ip + 5) == bblock))) {
+                                               (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));
@@ -5080,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);
@@ -5113,7 +5621,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        ADD_BINOP (*ip);
                        if (mono_find_jit_opcode_emulation (ins->opcode)) {
                                --sp;
-                               *sp++ = emit_tree (cfg, bblock, ins);
+                               *sp++ = emit_tree (cfg, bblock, ins, ip + 1);
                        }
                        ip++;
                        break;
@@ -5138,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);
@@ -5161,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);
                                }
@@ -5262,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);
@@ -5348,7 +5865,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                ins->inst_left = *sp;
                                ins->inst_newa_class = klass;
                                ins->cil_code = ip;
-                               *sp++ = emit_tree (cfg, bblock, ins);
+                               *sp++ = emit_tree (cfg, bblock, ins, ip + 6);
                                ip += 6;
                                break;
                        }
@@ -5361,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;
@@ -5425,7 +5952,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                 */
                                if (cmp->inst_left->type == STACK_I8) {
                                        --sp;
-                                       *sp++ = emit_tree (cfg, bblock, ins);
+                                       *sp++ = emit_tree (cfg, bblock, ins, ip + 2);
                                }
                                ip += 2;
                                break;
@@ -5440,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);
@@ -5468,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);
@@ -5562,6 +6089,13 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                --sp;
                                if (sp != stack_start) 
                                        goto unverified;
+                               if (cfg->method != method) 
+                                       /* 
+                                        * Inlining this into a loop in a parent could lead to 
+                                        * stack overflows which is different behavior than the
+                                        * non-inlined case, thus disable inlining in this case.
+                                        */
+                                       goto inline_failure;
                                MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
                                ins->inst_left = *sp;
                                ins->cil_code = ip;
@@ -5601,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;
                        }
@@ -5697,14 +6232,24 @@ 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;
                                ins->cil_code = ip;
                                MONO_ADD_INS (bblock, ins);
                                sp = stack_start;
+                               link_bblock (cfg, bblock, end_bblock);
                                start_new_bblock = 1;
                                ip += 2;
                                break;
@@ -5756,11 +6301,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
        bblock->cil_length = ip - bblock->cil_code;
        bblock->next_bb = end_bblock;
-       link_bblock (cfg, bblock, end_bblock);
 
        if (cfg->method == method && cfg->domainvar) {
-               
-               
                MonoInst *store;
                MonoInst *get_domain;
                
@@ -5778,6 +6320,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                MONO_ADD_INS (init_localsbb, store);
        }
 
+       if (cfg->method == method && cfg->got_var)
+               mono_emit_load_got_addr (cfg);
+
        if (header->init_locals) {
                MonoInst *store;
                for (i = 0; i < header->num_locals; ++i) {
@@ -5803,7 +6348,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                NEW_LOCSTORE (cfg, store, i, ins);
                                MONO_ADD_INS (init_localsbb, store);
                        } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
-                                  ((t == MONO_TYPE_GENERICINST) && mono_metadata_generic_inst_is_valuetype (ptype->data.generic_inst))) {
+                                  ((t == MONO_TYPE_GENERICINST) && mono_metadata_generic_class_is_valuetype (ptype->data.generic_class))) {
                                NEW_LOCLOADA (cfg, ins, i);
                                handle_initobj (cfg, init_localsbb, ins, NULL, mono_class_from_mono_type (ptype), NULL, NULL);
                                break;
@@ -5815,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;
@@ -5832,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)
@@ -5861,7 +6401,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
  unverified:
        if (cfg->method != method) 
                g_hash_table_destroy (bbhash);
-       g_error ("Invalid IL code at IL%04x in %s: %s\n", ip - header->code
+       g_error ("Invalid IL code at IL%04x in %s: %s\n", (int)(ip - header->code)
                 mono_method_full_name (method, TRUE), mono_disasm_code_one (NULL, method, ip, NULL));
        dont_inline = g_list_remove (dont_inline, method);
        return -1;
@@ -5880,10 +6420,10 @@ mono_print_tree (MonoInst *tree) {
 
        switch (tree->opcode) {
        case OP_ICONST:
-               printf ("[%d]", tree->inst_c0);
+               printf ("[%d]", (int)tree->inst_c0);
                break;
        case OP_I8CONST:
-               printf ("[%lld]", tree->inst_l);
+               printf ("[%lld]", (long long)tree->inst_l);
                break;
        case OP_R8CONST:
                printf ("[%f]", *(double*)tree->inst_p0);
@@ -5893,13 +6433,13 @@ mono_print_tree (MonoInst *tree) {
                break;
        case OP_ARG:
        case OP_LOCAL:
-               printf ("[%d]", tree->inst_c0);
+               printf ("[%d]", (int)tree->inst_c0);
                break;
        case OP_REGOFFSET:
                if (tree->inst_offset < 0)
-                       printf ("[-0x%x(%s)]", -tree->inst_offset, mono_arch_regname (tree->inst_basereg));
+                       printf ("[-0x%x(%s)]", (int)(-tree->inst_offset), mono_arch_regname (tree->inst_basereg));
                else
-                       printf ("[0x%x(%s)]", tree->inst_offset, mono_arch_regname (tree->inst_basereg));
+                       printf ("[0x%x(%s)]", (int)(tree->inst_offset), mono_arch_regname (tree->inst_basereg));
                break;
        case OP_REGVAR:
                printf ("[%s]", mono_arch_regname (tree->dreg));
@@ -5925,7 +6465,7 @@ mono_print_tree (MonoInst *tree) {
        }
        case OP_PHI: {
                int i;
-               printf ("[%d (", tree->inst_c0);
+               printf ("[%d (", (int)tree->inst_c0);
                for (i = 0; i < tree->inst_phi_args [0]; i++) {
                        if (i)
                                printf (", ");
@@ -5947,9 +6487,10 @@ mono_print_tree (MonoInst *tree) {
        case OP_LOADI1_MEMBASE:
        case OP_LOADU2_MEMBASE:
        case OP_LOADI2_MEMBASE:
-               printf ("[%s] <- [%s + 0x%x]", mono_arch_regname (tree->dreg), mono_arch_regname (tree->inst_basereg), tree->inst_offset);
+               printf ("[%s] <- [%s + 0x%x]", mono_arch_regname (tree->dreg), mono_arch_regname (tree->inst_basereg), (int)tree->inst_offset);
                break;
        case CEE_BR:
+       case OP_CALL_HANDLER:
                printf ("[B%d]", tree->inst_target_bb->block_num);
                break;
        case CEE_SWITCH:
@@ -6033,6 +6574,9 @@ create_helper_signature (void)
        /* void stelem_ref_check (MonoArray *, MonoObject *) */
        helper_sig_stelem_ref_check = make_icall_sig ("void object object");
 
+       /* void *helper_compile_generic_method (MonoObject *, MonoMethod *, MonoGenericContext *) */
+       helper_sig_compile_generic_method = make_icall_sig ("ptr object ptr ptr");
+
        /* long amethod (long, long) */
        helper_sig_long_long_long = make_icall_sig ("long long long");
 
@@ -6071,6 +6615,8 @@ create_helper_signature (void)
        /* intptr  amethod (intptr, intptr) */
        helper_sig_ptr_ptr_ptr = make_icall_sig ("ptr ptr ptr");
 
+       helper_sig_ptr_ptr_ptr_ptr = make_icall_sig ("ptr ptr ptr ptr");
+
        /* IntPtr  amethod (object) */
        helper_sig_ptr_obj = make_icall_sig ("ptr object");
 
@@ -6152,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)
@@ -6162,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);
 
@@ -6190,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;
@@ -6205,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;
@@ -6228,6 +6774,8 @@ mono_create_jit_trampoline (MonoMethod *method)
        if (domain == mono_get_root_domain ())
                method->info = tramp;
 
+       mono_jit_stats.method_trampolines++;
+
        return tramp;
 }      
 
@@ -6265,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)
 {
@@ -6443,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);
 
@@ -6527,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;
@@ -6644,15 +7352,15 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
                int i;
 
                if (method->dynamic) {
-                       jump_table = mono_code_manager_reserve (mono_dynamic_code_hash_lookup (domain, method)->code_mp, sizeof (gpointer) * patch_info->table_size);
+                       jump_table = mono_code_manager_reserve (mono_dynamic_code_hash_lookup (domain, method)->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
                } else {
                        mono_domain_lock (domain);
-                       jump_table = mono_code_manager_reserve (domain->code_mp, sizeof (gpointer) * patch_info->table_size);
+                       jump_table = mono_code_manager_reserve (domain->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
                        mono_domain_unlock (domain);
                }
 
-               for (i = 0; i < patch_info->table_size; i++) {
-                       jump_table [i] = code + (int)patch_info->data.table [i];
+               for (i = 0; i < patch_info->data.table->table_size; i++) {
+                       jump_table [i] = code + GPOINTER_TO_INT (patch_info->data.table->table [i]);
                }
                target = jump_table;
                break;
@@ -6665,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 = (gpointer)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);
@@ -6721,8 +7429,13 @@ 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:
+       case MONO_PATCH_INFO_NONE:
                break;
        default:
                g_assert_not_reached ();
@@ -6857,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)
 {
@@ -6873,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) 
@@ -6895,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
  *
@@ -6913,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);
@@ -6941,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;
@@ -7024,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) {
@@ -7066,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));
@@ -7095,8 +8051,12 @@ mono_compile_create_vars (MonoCompile *cfg)
        if (sig->hasthis)
                mono_compile_create_var (cfg, &cfg->method->klass->this_arg, OP_ARG);
 
-       for (i = 0; i < sig->param_count; ++i)
+       for (i = 0; i < sig->param_count; ++i) {
                mono_compile_create_var (cfg, sig->params [i], OP_ARG);
+               if (sig->params [i]->byref) {
+                       cfg->disable_ssa = TRUE;
+               }
+       }
 
        cfg->locals_start = cfg->num_varinfo;
 
@@ -7200,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 ();
@@ -7233,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;
@@ -7343,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;
@@ -7376,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)
@@ -7384,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) {
@@ -7415,18 +8372,20 @@ mono_codegen (MonoCompile *cfg)
                case MONO_PATCH_INFO_SWITCH: {
                        gpointer *table;
                        if (cfg->method->dynamic) {
-                               table = mono_code_manager_reserve (cfg->dynamic_info->code_mp, sizeof (gpointer) * patch_info->table_size);
+                               table = mono_code_manager_reserve (cfg->dynamic_info->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
                        } else {
                                mono_domain_lock (cfg->domain);
-                               table = mono_code_manager_reserve (cfg->domain->code_mp, sizeof (gpointer) * patch_info->table_size);
+                               table = mono_code_manager_reserve (cfg->domain->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
                                mono_domain_unlock (cfg->domain);
                        }
-               
-                       patch_info->ip.i = patch_info->ip.label->inst_c0;
-                       for (i = 0; i < patch_info->table_size; i++) {
-                               table [i] = (gpointer)patch_info->data.table [i]->native_offset;
+
+                       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++) {
+                               table [i] = GINT_TO_POINTER (patch_info->data.table->table [i]->native_offset);
                        }
-                       patch_info->data.target = table;
+                       patch_info->data.table->table = (MonoBasicBlock**)table;
                        break;
                }
                default:
@@ -7640,8 +8599,136 @@ 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) {
+                       int i;
+                       printf ("remove_critical_edges %s, BEFORE BB%d (in:", mono_method_full_name (cfg->method, TRUE), bb->block_num);
+                       for (i = 0; i < bb->in_count; i++) {
+                               printf (" %d", bb->in_bb [i]->block_num);
+                       }
+                       printf (") (out:");
+                       for (i = 0; i < bb->out_count; i++) {
+                               printf (" %d", bb->out_bb [i]->block_num);
+                       }
+                       printf (")");
+                       if (bb->last_ins != NULL) {
+                               printf (" ");
+                               mono_print_tree (bb->last_ins);
+                       }
+                       printf ("\n");
+               }
+       }
+       
+       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->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;
+                                                                       }
+                                                               }
+                                                       }
+                                               } 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);
+                                                       }
+                                               }
+                                       }
+                                       
+                                       /* 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), in_bb->block_num, bb->block_num, new_bb->block_num);
+                                       }
+                               }
+                       }
+               }
+       }
+       
+       if (cfg->verbose_level > 3) {
+               for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
+                       int i;
+                       printf ("remove_critical_edges %s, AFTER BB%d (in:", mono_method_full_name (cfg->method, TRUE), bb->block_num);
+                       for (i = 0; i < bb->in_count; i++) {
+                               printf (" %d", bb->in_bb [i]->block_num);
+                       }
+                       printf (") (out:");
+                       for (i = 0; i < bb->out_count; i++) {
+                               printf (" %d", bb->out_bb [i]->block_num);
+                       }
+                       printf (")");
+                       if (bb->last_ins != NULL) {
+                               printf (" ");
+                               mono_print_tree (bb->last_ins);
+                       }
+                       printf ("\n");
+               }
+       }
+}
+
 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;
@@ -7662,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);
 
@@ -7683,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 
@@ -7692,14 +8780,19 @@ 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);*/
 
-       /* Depth-first ordering on basic blocks */
-       cfg->bblocks = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * (cfg->num_bblocks + 1));
+       /*g_print ("numblocks = %d\n", cfg->num_bblocks);*/
 
        if (cfg->opt & MONO_OPT_BRANCH)
                optimize_branches (cfg);
 
+       if (cfg->opt & MONO_OPT_SSAPRE) {
+               remove_critical_edges (cfg);
+       }
+
+       /* Depth-first ordering on basic blocks */
+       cfg->bblocks = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * (cfg->num_bblocks + 1));
+
        df_visit (cfg->bb_entry, &dfn, cfg->bblocks);
        if (cfg->num_bblocks != dfn + 1) {
                MonoBasicBlock *bb;
@@ -7744,7 +8837,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
 #else 
 
        /* fixme: add all optimizations which requires SSA */
-       if (cfg->opt & (MONO_OPT_DEADCE | MONO_OPT_ABCREM)) {
+       if (cfg->opt & (MONO_OPT_DEADCE | MONO_OPT_ABCREM | MONO_OPT_SSAPRE)) {
                if (!(cfg->comp_done & MONO_COMP_SSA) && !header->num_clauses && !cfg->disable_ssa) {
                        mono_local_cprop (cfg);
                        mono_ssa_compute (cfg);
@@ -7760,7 +8853,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        if (parts == 2)
                return cfg;
 
-       if ((cfg->opt & MONO_OPT_CONSPROP) ||  (cfg->opt & MONO_OPT_COPYPROP)) {
+       if ((cfg->opt & MONO_OPT_CONSPROP) || (cfg->opt & MONO_OPT_COPYPROP)) {
                if (cfg->comp_done & MONO_COMP_SSA) {
                        mono_ssa_cprop (cfg);
                } else {
@@ -7775,7 +8868,10 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
 
                if ((cfg->flags & MONO_CFG_HAS_LDELEMA) && (cfg->opt & MONO_OPT_ABCREM))
                        mono_perform_abc_removal (cfg);
-
+               
+               if (cfg->opt & MONO_OPT_SSAPRE)
+                       mono_perform_ssapre (cfg);
+               
                mono_ssa_remove (cfg);
 
                if (cfg->opt & MONO_OPT_BRANCH)
@@ -7788,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;
 
@@ -7798,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);
@@ -7831,11 +8951,11 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        jinfo->code_size = cfg->code_len;
        jinfo->used_regs = cfg->used_int_regs;
        jinfo->domain_neutral = (cfg->opt & MONO_OPT_SHARED) != 0;
+       jinfo->cas_inited = FALSE; /* initialization delayed at the first stalk walk using this method */
 
        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);
@@ -7844,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);
@@ -7967,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);
 
@@ -8189,10 +9313,13 @@ static void
 SIG_HANDLER_SIGNATURE (sigfpe_signal_handler)
 {
        MonoException *exc = NULL;
+#ifndef MONO_ARCH_USE_SIGACTION
+       void *info = NULL;
+#endif
        GET_CONTEXT;
 
 #if defined(MONO_ARCH_HAVE_IS_INT_OVERFLOW)
-       if (mono_arch_is_int_overflow (ctx))
+       if (mono_arch_is_int_overflow (ctx, info))
                exc = mono_get_exception_arithmetic ();
        else
                exc = mono_get_exception_divide_by_zero ();
@@ -8257,10 +9384,18 @@ SIG_HANDLER_SIGNATURE (sigusr1_signal_handler)
        
        exc = mono_thread_request_interruption (running_managed); 
        if (!exc) return;
-       
+
        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)
 {
@@ -8346,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
  *
@@ -8375,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 ())
@@ -8385,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)
@@ -8410,12 +9631,16 @@ 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);
        mono_add_internal_call ("System.Diagnostics.StackTrace::get_trace", 
                                ves_icall_get_trace);
+       mono_add_internal_call ("System.Security.SecurityFrame::_GetSecurityFrame",
+                               ves_icall_System_Security_SecurityFrame_GetSecurityFrame);
+       mono_add_internal_call ("System.Security.SecurityFrame::_GetSecurityStack",
+                               ves_icall_System_Security_SecurityFrame_GetSecurityStack);
        mono_add_internal_call ("Mono.Runtime::mono_runtime_install_handlers", 
                                mono_runtime_install_handlers);
 
@@ -8439,8 +9664,13 @@ mini_init (const char *filename)
        mono_register_jit_icall (mono_arch_get_rethrow_exception (), "mono_arch_rethrow_exception", helper_sig_void_obj, TRUE);
        mono_register_jit_icall (mono_arch_get_throw_exception_by_name (), "mono_arch_throw_exception_by_name", 
                                 helper_sig_void_ptr, TRUE);
+#if MONO_ARCH_HAVE_THROW_CORLIB_EXCEPTION
+       mono_register_jit_icall (mono_arch_get_throw_corlib_exception (), "mono_arch_throw_corlib_exception", 
+                                helper_sig_void_ptr, TRUE);
+#endif
        mono_register_jit_icall (mono_thread_get_pending_exception, "mono_thread_get_pending_exception", helper_sig_obj_void, FALSE);
        mono_register_jit_icall (mono_thread_interruption_checkpoint, "mono_thread_interruption_checkpoint", helper_sig_void_void, FALSE);
+       mono_register_jit_icall (mono_thread_force_interruption_checkpoint, "mono_thread_force_interruption_checkpoint", helper_sig_void_void, FALSE);
        mono_register_jit_icall (mono_load_remote_field_new, "mono_load_remote_field_new", helper_sig_obj_obj_ptr_ptr, FALSE);
        mono_register_jit_icall (mono_store_remote_field_new, "mono_store_remote_field_new", helper_sig_void_obj_ptr_ptr_obj, FALSE);
 
@@ -8498,7 +9728,7 @@ mini_init (const char *filename)
        /* other jit icalls */
        mono_register_jit_icall (mono_class_static_field_address , "mono_class_static_field_address", 
                                 helper_sig_ptr_ptr_ptr, FALSE);
-       mono_register_jit_icall (mono_ldtoken_wrapper, "mono_ldtoken_wrapper", helper_sig_ptr_ptr_ptr, FALSE);
+       mono_register_jit_icall (mono_ldtoken_wrapper, "mono_ldtoken_wrapper", helper_sig_ptr_ptr_ptr_ptr, FALSE);
        mono_register_jit_icall (mono_get_special_static_data, "mono_get_special_static_data", helper_sig_ptr_int, FALSE);
        mono_register_jit_icall (mono_ldstr, "mono_ldstr", helper_sig_ldstr, FALSE);
        mono_register_jit_icall (helper_memcpy, "helper_memcpy", helper_sig_memcpy, FALSE);
@@ -8514,11 +9744,12 @@ mini_init (const char *filename)
        mono_register_jit_icall (mono_ldftn, "mono_ldftn", helper_sig_compile, FALSE);
        mono_register_jit_icall (mono_ldftn_nosync, "mono_ldftn_nosync", helper_sig_compile, FALSE);
        mono_register_jit_icall (mono_ldvirtfn, "mono_ldvirtfn", helper_sig_compile_virt, FALSE);
+       mono_register_jit_icall (helper_compile_generic_method, "compile_generic_method", helper_sig_compile_generic_method, FALSE);
 #endif
 
 #define JIT_RUNTIME_WORKS
 #ifdef JIT_RUNTIME_WORKS
-       mono_runtime_install_cleanup ((MonoDomainFunc)mini_cleanup);
+       mono_install_runtime_cleanup ((MonoDomainFunc)mini_cleanup);
        mono_runtime_init (domain, mono_thread_start_cb, mono_thread_attach_cb);
 #endif
 
@@ -8559,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);
        }
@@ -8568,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
@@ -8582,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 ();
 }