* ProtectedConfigurationProvider.cs:
[mono.git] / mono / mini / mini.c
index e35c03dd6d6edcaa248c7e20b5c63d07f730d81e..353268e25e44155a22ab07fb6de8ecbf93411eae 100644 (file)
 #include <unistd.h>
 #include <math.h>
 
+#ifdef sun    // Solaris x86
+#include <sys/types.h>
+#include <sys/ucontext.h>
+#endif
+
 #ifdef HAVE_VALGRIND_MEMCHECK_H
 #include <valgrind/memcheck.h>
 #endif
@@ -40,6 +45,7 @@
 #include <mono/metadata/environment.h>
 #include <mono/metadata/mono-debug.h>
 #include <mono/metadata/mono-debug-debugger.h>
+#include <mono/metadata/monitor.h>
 
 #include "mini.h"
 #include <string.h>
 
 #include "jit-icalls.c"
 
-#define MONO_IS_COND_BRANCH(op) ((op >= CEE_BEQ && op <= CEE_BLT_UN) || (op >= OP_LBEQ && op <= OP_LBLT_UN) || (op >= OP_FBEQ && op <= OP_FBLT_UN))
+/* 
+ * this is used to determine when some branch optimizations are possible: we exclude FP compares
+ * because they have weird semantics with NaNs.
+ */
+#define MONO_IS_COND_BRANCH_OP(ins) (((ins)->opcode >= CEE_BEQ && (ins)->opcode <= CEE_BLT_UN) || ((ins)->opcode >= OP_LBEQ && (ins)->opcode <= OP_LBLT_UN) || ((ins)->opcode >= OP_FBEQ && (ins)->opcode <= OP_FBLT_UN) || ((ins)->opcode >= OP_IBEQ && (ins)->opcode <= OP_IBLT_UN))
+#define MONO_IS_COND_BRANCH_NOFP(ins) (MONO_IS_COND_BRANCH_OP(ins) && (ins)->inst_left->inst_left->type != STACK_R8)
 
 #define MONO_CHECK_THIS(ins) (cfg->method->signature->hasthis && (ins)->ssa_op == MONO_SSA_LOAD && (ins)->inst_left->inst_c0 == 0)
 
-gboolean  mono_arch_handle_exception (struct sigcontext *ctx, gpointer obj, gboolean test_only);
+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);
 static gpointer mono_jit_find_compiled_method (MonoDomain *domain, MonoMethod *method);
@@ -80,14 +91,20 @@ static MonoMethodSignature *helper_sig_object_new_specific = NULL;
 static MonoMethodSignature *helper_sig_compile = NULL;
 static MonoMethodSignature *helper_sig_compile_virt = NULL;
 static MonoMethodSignature *helper_sig_obj_ptr = NULL;
+static MonoMethodSignature *helper_sig_obj_ptr_ptr = NULL;
+static MonoMethodSignature *helper_sig_obj_obj_ptr_ptr = NULL;
 static MonoMethodSignature *helper_sig_obj_void = NULL;
 static MonoMethodSignature *helper_sig_ptr_void = NULL;
+static MonoMethodSignature *helper_sig_void_void = NULL;
 static MonoMethodSignature *helper_sig_void_ptr = NULL;
 static MonoMethodSignature *helper_sig_void_obj = NULL;
+static MonoMethodSignature *helper_sig_void_obj_ptr_int = NULL;
+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_obj = NULL;
+static MonoMethodSignature *helper_sig_ptr_obj_int = NULL;
 static MonoMethodSignature *helper_sig_ptr_int = NULL;
 static MonoMethodSignature *helper_sig_initobj = NULL;
 static MonoMethodSignature *helper_sig_memcpy = NULL;
@@ -95,6 +112,7 @@ static MonoMethodSignature *helper_sig_memset = NULL;
 static MonoMethodSignature *helper_sig_ulong_double = NULL;
 static MonoMethodSignature *helper_sig_long_double = NULL;
 static MonoMethodSignature *helper_sig_double_long = NULL;
+static MonoMethodSignature *helper_sig_double_int = NULL;
 static MonoMethodSignature *helper_sig_float_long = NULL;
 static MonoMethodSignature *helper_sig_double_double_double = NULL;
 static MonoMethodSignature *helper_sig_uint_double = NULL;
@@ -102,7 +120,6 @@ 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_obj_obj_cls = NULL;
 
 static guint32 default_opt = MONO_OPT_PEEPHOLE;
 
@@ -132,74 +149,6 @@ mono_running_on_valgrind (void)
 #endif
 }
 
-#ifdef MONO_USE_EXC_TABLES
-static gboolean
-mono_type_blittable (MonoType *type)
-{
-       if (type->byref)
-               return FALSE;
-
-       switch (type->type){
-       case MONO_TYPE_VOID:
-       case MONO_TYPE_I1:
-       case MONO_TYPE_U1:
-       case MONO_TYPE_I2:
-       case MONO_TYPE_U2:
-       case MONO_TYPE_I4:
-       case MONO_TYPE_U4:
-       case MONO_TYPE_I8:
-       case MONO_TYPE_U8:
-       case MONO_TYPE_R4:
-       case MONO_TYPE_R8:
-       case MONO_TYPE_I:
-       case MONO_TYPE_U:
-               return TRUE;
-       case MONO_TYPE_VALUETYPE:
-       case MONO_TYPE_CLASS:
-               return type->data.klass->blittable;
-               break;
-       default:
-               break;
-       }
-
-       return FALSE;
-}
-
-gboolean
-mono_method_blittable (MonoMethod *method)
-{
-       MonoMethodSignature *sig;
-       int i;
-
-       if (!method->addr)
-               return FALSE;
-
-       if (!mono_arch_has_unwind_info (method->addr)) {
-               return FALSE;
-       }
-
-       if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)
-               return TRUE;
-
-       sig = method->signature;
-
-       if (!mono_type_blittable (sig->ret))
-               return FALSE;
-
-       for (i = 0; i < sig->param_count; i++)
-               if (!mono_type_blittable (sig->params [i]))
-                       return FALSE;
-
-       if (mono_method_has_marshal_info (method))
-               return FALSE;
-
-        if ((method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) && ((MonoMethodPInvoke*)method)->piflags & PINVOKE_ATTRIBUTE_SUPPORTS_LAST_ERROR)
-        return FALSE;
-
-       return TRUE;
-}
-#endif
-
 /* debug function */
 G_GNUC_UNUSED static void
 print_method_from_ip (void *ip)
@@ -227,6 +176,12 @@ print_method_from_ip (void *ip)
 
 }
 
+G_GNUC_UNUSED void
+mono_print_method_from_ip (void *ip)
+{
+       print_method_from_ip (ip);
+}
+       
 /* 
  * mono_method_same_domain:
  *
@@ -289,8 +244,7 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
                        (tblock) = NEW_BBLOCK (cfg);    \
                        (tblock)->cil_code = (ip);      \
                        ADD_BBLOCK (cfg, (bbhash), (tblock));   \
-               }       \
-               (tblock)->real_offset = real_offset; \
+               } \
        } while (0)
 
 #define CHECK_BBLOCK(target,ip,tblock) do {    \
@@ -307,17 +261,31 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
                (dest)->type = STACK_I4;        \
        } while (0)
 
-/* FIXME: have a different definition of NEW_PCONST for 64 bit systems */
+#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)->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_ICONST;    \
+               (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;       \
@@ -325,7 +293,7 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
 
 #define NEW_IMAGECONST(cfg,dest,val) do {      \
                (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
-               (dest)->opcode = mono_compile_aot ? OP_AOTCONST : OP_ICONST;    \
+               (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;       \
@@ -333,7 +301,7 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
 
 #define NEW_FIELDCONST(cfg,dest,field) do {    \
                (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
-               (dest)->opcode = mono_compile_aot ? OP_AOTCONST : OP_ICONST;    \
+               (dest)->opcode = mono_compile_aot ? OP_AOTCONST : OP_PCONST;    \
                (dest)->inst_p0 = (field);      \
                (dest)->inst_i1 = (gpointer)MONO_PATCH_INFO_FIELD; \
                (dest)->type = STACK_PTR;       \
@@ -341,7 +309,7 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
 
 #define NEW_METHODCONST(cfg,dest,val) do {     \
                (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
-               (dest)->opcode = mono_compile_aot ? OP_AOTCONST : OP_ICONST;    \
+               (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;       \
@@ -349,7 +317,7 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
 
 #define NEW_VTABLECONST(cfg,dest,vtable) do {  \
                (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
-               (dest)->opcode = mono_compile_aot ? OP_AOTCONST : OP_ICONST;    \
+               (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;       \
@@ -357,7 +325,7 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
 
 #define NEW_SFLDACONST(cfg,dest,field) do {    \
                (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
-               (dest)->opcode = mono_compile_aot ? OP_AOTCONST : OP_ICONST;    \
+               (dest)->opcode = mono_compile_aot ? OP_AOTCONST : OP_PCONST;    \
                (dest)->inst_p0 = (field);      \
                (dest)->inst_i1 = (gpointer)MONO_PATCH_INFO_SFLDA; \
                (dest)->type = STACK_PTR;       \
@@ -540,8 +508,8 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
 
 #define ADD_BINCOND(next_block) do {   \
                MonoInst *cmp;  \
-               MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
                sp -= 2;                \
+               MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
                cmp->inst_i0 = sp [0];  \
                cmp->inst_i1 = sp [1];  \
                cmp->cil_code = ins->cil_code;  \
@@ -569,8 +537,8 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
 /* FIXME: handle float, long ... */
 #define ADD_UNCOND(istrue) do {        \
                MonoInst *cmp;  \
-               MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
                sp--;           \
+               MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
                cmp->inst_i0 = sp [0];  \
                 switch (cmp->inst_i0->type) { \
                case STACK_I8: \
@@ -609,6 +577,7 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
                (dest)->inst_right = (sp) [1];  \
                (dest)->type = STACK_MP;        \
                (dest)->klass = (k);    \
+               (cfg)->flags |= MONO_CFG_HAS_LDELEMA; \
        } while (0)
 
 #define NEW_GROUP(cfg,dest,el1,el2) do {       \
@@ -1133,37 +1102,37 @@ shift_table [STACK_MAX] [STACK_MAX] = {
 /* handles from CEE_ADD to CEE_SHR_UN (CEE_REM_UN for floats) */
 static const guint16
 binops_op_map [STACK_MAX] = {
-       0, 0, OP_LADD-CEE_ADD, OP_PADD-CEE_ADD, OP_FADD-CEE_ADD, 0
+       0, 0, OP_LADD-CEE_ADD, OP_PADD-CEE_ADD, OP_FADD-CEE_ADD, OP_PADD-CEE_ADD
 };
 
 /* handles from CEE_NEG to CEE_CONV_U8 */
 static const guint16
 unops_op_map [STACK_MAX] = {
-       0, 0, OP_LNEG-CEE_NEG, OP_PNEG-CEE_NEG, OP_FNEG-CEE_NEG, 0
+       0, 0, OP_LNEG-CEE_NEG, OP_PNEG-CEE_NEG, OP_FNEG-CEE_NEG, OP_PNEG-CEE_NEG
 };
 
 /* handles from CEE_CONV_U2 to CEE_SUB_OVF_UN */
 static const guint16
 ovfops_op_map [STACK_MAX] = {
-       0, 0, OP_LCONV_TO_U2-CEE_CONV_U2, OP_PCONV_TO_U2-CEE_CONV_U2, OP_FCONV_TO_U2-CEE_CONV_U2, 0
+       0, 0, OP_LCONV_TO_U2-CEE_CONV_U2, OP_PCONV_TO_U2-CEE_CONV_U2, OP_FCONV_TO_U2-CEE_CONV_U2, OP_PCONV_TO_U2-CEE_CONV_U2
 };
 
 /* handles from CEE_CONV_OVF_I1_UN to CEE_CONV_OVF_U_UN */
 static const guint16
 ovf2ops_op_map [STACK_MAX] = {
-       0, 0, OP_LCONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN, OP_PCONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN, OP_FCONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN, 0
+       0, 0, OP_LCONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN, OP_PCONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN, OP_FCONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN, OP_PCONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN
 };
 
 /* handles from CEE_CONV_OVF_I1 to CEE_CONV_OVF_U8 */
 static const guint16
 ovf3ops_op_map [STACK_MAX] = {
-       0, 0, OP_LCONV_TO_OVF_I1-CEE_CONV_OVF_I1, OP_PCONV_TO_OVF_I1-CEE_CONV_OVF_I1, OP_FCONV_TO_OVF_I1-CEE_CONV_OVF_I1, 0
+       0, 0, OP_LCONV_TO_OVF_I1-CEE_CONV_OVF_I1, OP_PCONV_TO_OVF_I1-CEE_CONV_OVF_I1, OP_FCONV_TO_OVF_I1-CEE_CONV_OVF_I1, OP_PCONV_TO_OVF_I1-CEE_CONV_OVF_I1
 };
 
 /* handles from CEE_CEQ to CEE_CLT_UN */
 static const guint16
 ceqops_op_map [STACK_MAX] = {
-       0, 0, OP_LCEQ-CEE_CEQ, OP_PCEQ-CEE_CEQ, OP_FCEQ-CEE_CEQ, 0
+       0, 0, OP_LCEQ-CEE_CEQ, OP_PCEQ-CEE_CEQ, OP_FCEQ-CEE_CEQ, OP_LCEQ-CEE_CEQ
 };
 
 /*
@@ -1202,8 +1171,11 @@ type_from_op (MonoInst *ins) {
                ins->opcode += binops_op_map [ins->type];
                return;
        case OP_COMPARE:
+       case OP_LCOMPARE:
                /* FIXME: handle some specifics with ins->next->type */
                ins->type = bin_comp_table [ins->inst_i0->type] [ins->inst_i1->type] ? STACK_I4: STACK_INV;
+               if ((ins->inst_i0->type == STACK_I8) || ((sizeof (gpointer) == 8) && ((ins->inst_i0->type == STACK_PTR) || (ins->inst_i0->type == STACK_OBJ) || (ins->inst_i0->type == STACK_MP))))
+                       ins->opcode = OP_LCOMPARE;
                return;
        case OP_CEQ:
        case OP_CGT:
@@ -1627,28 +1599,32 @@ mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins)
  * at basic block boundaries. What happens is that we save the values to local variables
  * and we reload them later when first entering the target basic block (with the
  * handle_loaded_temps () function).
+ * It is also used to handle items on the stack in store opcodes, since it is
+ * possible that the variable to be stored into is already on the stack, in
+ * which case its old value should be used.
  * A single joint point will use the same variables (stored in the array bb->out_stack or
  * bb->in_stack, if the basic block is before or after the joint point).
  */
 static int
 handle_stack_args (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **sp, int count) {
-       int i;
+       int i, bindex;
        MonoBasicBlock *outb;
        MonoInst *inst, **locals;
+       gboolean found;
 
        if (!count)
                return 0;
        if (cfg->verbose_level > 3)
                g_print ("%d item(s) on exit from B%d\n", count, bb->block_num);
        if (!bb->out_scount) {
-               int found = 0;
                bb->out_scount = count;
                //g_print ("bblock %d has out:", bb->block_num);
+               found = FALSE;
                for (i = 0; i < bb->out_count; ++i) {
                        outb = bb->out_bb [i];
                        //g_print (" %d", outb->block_num);
                        if (outb->in_stack) {
-                               found = 1;
+                               found = TRUE;
                                bb->out_stack = outb->in_stack;
                                break;
                        }
@@ -1657,16 +1633,34 @@ handle_stack_args (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **sp, int coun
                if (!found) {
                        bb->out_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
                        for (i = 0; i < count; ++i) {
-#if 1
-                               /* try to reuse temps already allocated for this purpouse, if they occupy the same 
-                                * stack slot and if they are of the same type. */
-                               bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
-#else
-                               bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
-#endif
+                               /* 
+                                * try to reuse temps already allocated for this purpouse, if they occupy the same
+                                * stack slot and if they are of the same type.
+                                * This won't cause conflicts since if 'local' is used to 
+                                * store one of the values in the in_stack of a bblock, then
+                                * the same variable will be used for the same outgoing stack 
+                                * slot as well. 
+                                * This doesn't work when inlining methods, since the bblocks
+                                * in the inlined methods do not inherit their in_stack from
+                                * the bblock they are inlined to. See bug #58863 for an
+                                * example.
+                                */
+                               if (cfg->inlined_method)
+                                       bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
+                               else
+                                       bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
                        }
                }
        }
+
+       for (i = 0; i < bb->out_count; ++i) {
+               outb = bb->out_bb [i];
+               if (outb->in_scount)
+                       continue; /* check they are the same locals */
+               outb->in_scount = count;
+               outb->in_stack = bb->out_stack;
+       }
+
        locals = bb->out_stack;
        for (i = 0; i < count; ++i) {
                /* add store ops at the end of the bb, before the branch */
@@ -1681,27 +1675,47 @@ handle_stack_args (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **sp, int coun
                if (cfg->verbose_level > 3)
                        g_print ("storing %d to temp %d\n", i, locals [i]->inst_c0);
        }
-       
-       for (i = 0; i < bb->out_count; ++i) {
-               outb = bb->out_bb [i];
-               if (outb->in_scount)
-                       continue; /* check they are the same locals */
-               outb->in_scount = count;
-               outb->in_stack = locals;
+
+       /*
+        * It is possible that the out bblocks already have in_stack assigned, and
+        * the in_stacks differ. In this case, we will store to all the different 
+        * in_stacks.
+        */
+
+       found = TRUE;
+       bindex = 0;
+       while (found) {
+               /* Find a bblock which has a different in_stack */
+               found = FALSE;
+               while (bindex < bb->out_count) {
+                       outb = bb->out_bb [bindex];
+                       if (outb->in_stack != locals) {
+                               /* 
+                                * Instead of storing sp [i] to locals [i], we need to store
+                                * locals [i] to <new locals>[i], since the sp [i] tree can't
+                                * be shared between trees.
+                                */
+                               for (i = 0; i < count; ++i)
+                                       mono_add_varcopy_to_end (cfg, bb, locals [i]->inst_c0, outb->in_stack [i]->inst_c0);
+                               locals = outb->in_stack;
+                               found = TRUE;
+                               break;
+                       }
+                       bindex ++;
+               }
        }
+       
        return 0;
 }
 
 static int
 ret_type_to_call_opcode (MonoType *type, int calli, int virt)
 {
-       int t = type->type;
-
        if (type->byref)
                return calli? OP_CALL_REG: virt? CEE_CALLVIRT: CEE_CALL;
 
 handle_enum:
-       switch (t) {
+       switch (type->type) {
        case MONO_TYPE_VOID:
                return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALLVIRT: OP_VOIDCALL;
        case MONO_TYPE_I1:
@@ -1731,14 +1745,14 @@ handle_enum:
                return calli? OP_FCALL_REG: virt? OP_FCALLVIRT: OP_FCALL;
        case MONO_TYPE_VALUETYPE:
                if (type->data.klass->enumtype) {
-                       t = type->data.klass->enum_basetype->type;
+                       type = type->data.klass->enum_basetype;
                        goto handle_enum;
                } else
                        return calli? OP_VCALL_REG: virt? OP_VCALLVIRT: OP_VCALL;
        case MONO_TYPE_TYPEDBYREF:
                return calli? OP_VCALL_REG: virt? OP_VCALLVIRT: OP_VCALL;
        case MONO_TYPE_GENERICINST:
-               t = type->data.generic_inst->generic_type->type;
+               type = type->data.generic_inst->generic_type;
                goto handle_enum;
        default:
                g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
@@ -1802,7 +1816,8 @@ handle_loaded_temps (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst **stack,
 static int
 check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
 {
-       int i, simple_type;
+       MonoType *simple_type;
+       int i;
 
        if (sig->hasthis) {
                if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
@@ -1834,9 +1849,9 @@ check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **arg
                                return 1;
                        continue;
                }
-               simple_type = sig->params [i]->type;
+               simple_type = sig->params [i];
 handle_enum:
-               switch (simple_type) {
+               switch (simple_type->type) {
                case MONO_TYPE_VOID:
                        return 1;
                        continue;
@@ -1876,8 +1891,8 @@ handle_enum:
                                return 1;
                        continue;
                case MONO_TYPE_VALUETYPE:
-                       if (sig->params [i]->data.klass->enumtype) {
-                               simple_type = sig->params [i]->data.klass->enum_basetype->type;
+                       if (simple_type->data.klass->enumtype) {
+                               simple_type = simple_type->data.klass->enum_basetype;
                                goto handle_enum;
                        }
                        if (args [i]->type != STACK_VTYPE)
@@ -1888,11 +1903,12 @@ handle_enum:
                                return 1;
                        continue;
                case MONO_TYPE_GENERICINST:
-                       simple_type = sig->params [i]->data.generic_inst->generic_type->type;
+                       simple_type = sig->params [i]->data.generic_inst->generic_type;
                        goto handle_enum;
 
                default:
-                       g_error ("unknown type 0x%02x in check_call_signature", simple_type);
+                       g_error ("unknown type 0x%02x in check_call_signature",
+                                simple_type->type);
                }
        }
        return 0;
@@ -2112,15 +2128,22 @@ mono_get_element_address_signature (int arity)
        MonoMethodSignature *res;
        int i;
 
-       if (!sighash)
+       EnterCriticalSection (&trampoline_hash_mutex);
+       if (!sighash) {
                sighash = g_hash_table_new (NULL, NULL);
-
-
-       if ((res = g_hash_table_lookup (sighash, (gpointer)arity)))
+       }
+       else if ((res = g_hash_table_lookup (sighash, (gpointer)arity))) {
+               LeaveCriticalSection (&trampoline_hash_mutex);
                return res;
+       }
 
        res = mono_metadata_signature_alloc (mono_defaults.corlib, arity + 1);
 
+       res->pinvoke = 1;
+#ifdef MONO_ARCH_VARARG_ICALLS
+       /* Only set this only some archs since not all backends can handle varargs+pinvoke */
+       res->call_convention = MONO_CALL_VARARG;
+#endif
        res->params [0] = &mono_defaults.array_class->byval_arg; 
        
        for (i = 1; i <= arity; i++)
@@ -2129,6 +2152,43 @@ mono_get_element_address_signature (int arity)
        res->ret = &mono_defaults.int_class->byval_arg;
 
        g_hash_table_insert (sighash, (gpointer)arity, res);
+       LeaveCriticalSection (&trampoline_hash_mutex);
+
+       return res;
+}
+
+static MonoMethodSignature *
+mono_get_array_new_va_signature (int arity)
+{
+       static GHashTable *sighash = NULL;
+       MonoMethodSignature *res;
+       int i;
+
+       EnterCriticalSection (&trampoline_hash_mutex);
+       if (!sighash) {
+               sighash = g_hash_table_new (NULL, NULL);
+       }
+       else if ((res = g_hash_table_lookup (sighash, (gpointer)arity))) {
+               LeaveCriticalSection (&trampoline_hash_mutex);
+               return res;
+       }
+
+       res = mono_metadata_signature_alloc (mono_defaults.corlib, arity + 1);
+
+       res->pinvoke = 1;
+#ifdef MONO_ARCH_VARARG_ICALLS
+       /* Only set this only some archs since not all backends can handle varargs+pinvoke */
+       res->call_convention = MONO_CALL_VARARG;
+#endif
+
+       res->params [0] = &mono_defaults.int_class->byval_arg;  
+       for (i = 0; i < arity; i++)
+               res->params [i + 1] = &mono_defaults.int_class->byval_arg;
+
+       res->ret = &mono_defaults.int_class->byval_arg;
+
+       g_hash_table_insert (sighash, (gpointer)arity, res);
+       LeaveCriticalSection (&trampoline_hash_mutex);
 
        return res;
 }
@@ -2212,6 +2272,49 @@ handle_initobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, const
        }
 }
 
+static MonoInst *
+handle_box (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *val, const guchar *ip, MonoClass *klass)
+{
+       MonoInst *iargs [2];
+       MonoInst *dest, *vtoffset, *add, *vstore;
+       int temp;
+
+       /* much like NEWOBJ */
+       if (cfg->opt & MONO_OPT_SHARED) {
+               NEW_DOMAINCONST (cfg, iargs [0]);
+               NEW_CLASSCONST (cfg, iargs [1], klass);
+
+               temp = mono_emit_jit_icall (cfg, bblock, mono_object_new, iargs, ip);
+       } else {
+               MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
+               NEW_VTABLECONST (cfg, iargs [0], vtable);
+               if (klass->has_finalize || (cfg->prof_options & MONO_PROFILE_ALLOCATIONS))
+                       temp = mono_emit_jit_icall (cfg, bblock, mono_object_new_specific, iargs, ip);
+               else
+                       temp = mono_emit_jit_icall (cfg, bblock, mono_object_new_fast, iargs, ip);
+       }
+       NEW_TEMPLOAD (cfg, dest, temp);
+       NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
+       MONO_INST_NEW (cfg, add, OP_PADD);
+       add->inst_left = dest;
+       add->inst_right = vtoffset;
+       add->cil_code = ip;
+       add->klass = klass;
+       MONO_INST_NEW (cfg, vstore, CEE_STIND_I);
+       vstore->opcode = mono_type_to_stind (&klass->byval_arg);
+       vstore->cil_code = ip;
+       vstore->inst_left = add;
+       vstore->inst_right = val;
+
+       if (vstore->opcode == CEE_STOBJ) {
+               handle_stobj (cfg, bblock, add, val, ip, klass, FALSE, FALSE);
+       } else
+               MONO_ADD_INS (bblock, vstore);
+
+       NEW_TEMPLOAD (cfg, dest, temp);
+       return dest;
+}
+
 #define CODE_IS_STLOC(ip) (((ip) [0] >= CEE_STLOC_0 && (ip) [0] <= CEE_STLOC_3) || ((ip) [0] == CEE_STLOC_S))
 
 static gboolean
@@ -2222,6 +2325,13 @@ mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
        MonoVTable *vtable;
        int i;
 
+#ifdef MONO_ARCH_HAVE_LMF_OPS
+       if (((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
+                (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) &&
+           !MONO_TYPE_ISSTRUCT (signature->ret) && (method->klass->parent != mono_defaults.array_class))
+               return TRUE;
+#endif
+
        if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
            (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
            (method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
@@ -2283,6 +2393,8 @@ mini_get_ldelema_ins (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *cmet
        int temp, rank;
        MonoInst *addr;
        MonoMethodSignature *esig;
+       char icall_name [256];
+       MonoJitICallInfo *info;
 
        rank = cmethod->signature->param_count - (is_set? 1: 0);
 
@@ -2297,8 +2409,19 @@ mini_get_ldelema_ins (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *cmet
                addr->klass = cmethod->klass;
                return addr;
        }
-       esig = mono_get_element_address_signature (rank);
-       temp = mono_emit_native_call (cfg, bblock, ves_array_element_address, esig, sp, ip, FALSE);
+
+       /* Need to register the icall so it gets an icall wrapper */
+       sprintf (icall_name, "ves_array_element_address_%d", rank);
+
+       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);
+       }
+
+       temp = mono_emit_native_call (cfg, bblock, mono_icall_get_wrapper (info), info->sig, sp, ip, FALSE);
+       cfg->flags |= MONO_CFG_HAS_VARARGS;
+
        NEW_TEMPLOAD (cfg, addr, temp);
        return addr;
 }
@@ -2319,6 +2442,11 @@ mini_get_opcode_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSig
 {
        int pc, op;
        MonoInst *ins;
+       
+       static MonoClass *runtime_helpers_class = NULL;
+       if (! runtime_helpers_class)
+               runtime_helpers_class = mono_class_from_name (mono_defaults.corlib,
+                       "System.Runtime.CompilerServices", "RuntimeHelpers");
 
        if (cmethod->klass == mono_defaults.string_class) {
                if (cmethod->name [0] != 'g')
@@ -2341,6 +2469,12 @@ mini_get_opcode_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSig
                        op = CEE_LDLEN;
                else
                        return NULL;
+       } else if (cmethod->klass == runtime_helpers_class) {
+               if (strcmp (cmethod->name, "get_OffsetToStringData") == 0) {
+                       NEW_ICONST (cfg, ins, G_STRUCT_OFFSET (MonoString, chars));
+                       return ins;
+               } else
+                       return NULL;
        } else {
                op = mono_arch_get_opcode_for_method (cfg, cmethod, fsig, args);
                if (op < 0)
@@ -2403,18 +2537,17 @@ mono_save_args (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *s
 
 static int
 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoBasicBlock *bblock, MonoInst **sp,
-               guchar *ip, guint real_offset, GList *dont_inline, MonoBasicBlock **last_b)
+               guchar *ip, guint real_offset, GList *dont_inline, MonoBasicBlock **last_b, gboolean inline_allways)
 {
        MonoInst *ins, *rvar = NULL;
        MonoMethodHeader *cheader;
        MonoBasicBlock *ebblock, *sbblock;
        int i, costs, new_locals_offset;
+       MonoMethod *prev_inlined_method;
 
        if (cfg->verbose_level > 2)
                g_print ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
 
-       cheader = ((MonoMethodNormal *)cmethod)->header;
-
        if (!cmethod->inline_info) {
                mono_jit_stats.inlineable_methods++;
                cmethod->inline_info = 1;
@@ -2425,6 +2558,7 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig,
        }
 
        /* allocate local variables */
+       cheader = ((MonoMethodNormal *)cmethod)->header;
        new_locals_offset = cfg->num_varinfo;
        for (i = 0; i < cheader->num_locals; ++i)
                mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
@@ -2438,9 +2572,14 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig,
        ebblock->block_num = cfg->num_bblocks++;
        ebblock->real_offset = real_offset;
 
+       prev_inlined_method = cfg->inlined_method;
+       cfg->inlined_method = cmethod;
+
        costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, new_locals_offset, rvar, dont_inline, sp, real_offset, *ip == CEE_CALLVIRT);
 
-       if (costs >= 0 && costs < 60) {
+       cfg->inlined_method = prev_inlined_method;
+
+       if ((costs >= 0 && costs < 60) || inline_allways) {
                if (cfg->verbose_level > 2)
                        g_print ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
                
@@ -2500,12 +2639,6 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig,
 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) goto unverified
 #define CHECK_OPSIZE(size) if (ip + size > end) goto unverified
 
-#define TYPE_PARAM_TO_TYPE(num) (method->klass->generic_inst->type_argv [(num)])
-#define TYPE_PARAM_TO_CLASS(num) (mono_class_from_mono_type (TYPE_PARAM_TO_TYPE ((num))))
-
-#define MTYPE_PARAM_TO_TYPE(num) (method->signature->gen_method->mtype_argv [(num)])
-#define MTYPE_PARAM_TO_CLASS(num) (mono_class_from_mono_type (MTYPE_PARAM_TO_TYPE ((num))))
-
 
 /* offset from br.s -> br like opcodes */
 #define BIG_BRANCH_OFFSET 13
@@ -2522,7 +2655,9 @@ get_basic_blocks (MonoCompile *cfg, GHashTable *bbhash, MonoMethodHeader* header
 
        while (ip < end) {
                cli_addr = ip - start;
-               i = mono_opcode_value ((const guint8 **)&ip);
+               i = mono_opcode_value ((const guint8 **)&ip, end);
+               if (i < 0)
+                       goto unverified;
                opcode = &mono_opcodes [i];
                switch (opcode->argument) {
                case MonoInlineNone:
@@ -2584,47 +2719,17 @@ unverified:
        return 1;
 }
 
-static MonoClassField *
-get_generic_field_inst (MonoClassField *field, MonoClass *klass, MonoClass **retclass)
-{
-       int i;
-       for (i = 0; i < field->parent->field.count; ++i) {
-               if (field == &field->parent->fields [i]) {
-                       *retclass = klass;
-                       return &klass->fields [i];
-               }
-       }
-       return NULL;
-}
-
-static MonoClassField *
-inflate_generic_field (MonoClassField *field, MonoClass *klass, MonoClass **retclass)
-{
-       MonoGenericInst *ginst;
-       MonoClassField *res;
-
-       res = g_new0 (MonoClassField, 1);
-       *res = *field;
-       ginst = klass->generic_inst;
-       res->type = mono_class_inflate_generic_type (field->type, ginst, NULL);
-       return res;
-}
-
-static MonoMethod *
-mini_get_method (MonoImage *image, guint32 token, MonoMethod *calling_method)
+static MonoInst*
+emit_tree (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ins)
 {
-       MonoMethod *method = mono_get_method (image, token, NULL);
-       MonoGenericMethod *gmethod;
-
-       if (!calling_method->signature->gen_method || !method->signature->gen_method)
-               return method;
-
-       gmethod = g_new0 (MonoGenericMethod, 1);
-       *gmethod = *calling_method->signature->gen_method;
-       gmethod->generic_method = method;
-       gmethod->generic_inst = calling_method->klass->generic_inst;
-
-       return mono_class_inflate_generic_method (method, gmethod, NULL);
+       MonoInst *store, *temp, *load;
+       temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
+       NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
+       store->cil_code = ins->cil_code;
+       MONO_ADD_INS (bblock, store);
+       NEW_TEMPLOAD (cfg, load, temp->inst_c0);
+       load->cil_code = ins->cil_code;
+       return load;
 }
 
 /*
@@ -2645,9 +2750,11 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
        MonoImage *image;
        guint32 token, ins_flag;
        MonoClass *klass;
+       MonoClass *constrained_call = NULL;
        unsigned char *ip, *end, *target, *err_pos;
        static double r8_0 = 0.0;
        MonoMethodSignature *sig;
+       MonoGenericContext *generic_context = NULL;
        MonoType **param_types;
        GList *bb_recheck = NULL, *tmp;
        int i, n, start_new_bblock, align;
@@ -2664,6 +2771,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
        end = ip + header->code_size;
        mono_jit_stats.cil_code_size += header->code_size;
 
+       if (method->signature->is_inflated)
+               generic_context = ((MonoMethodInflated *) method)->context;
+
        if (cfg->method == method) {
                real_offset = 0;
                bbhash = cfg->bb_hash;
@@ -2675,12 +2785,12 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
        if (cfg->verbose_level > 2)
                g_print ("method to IR %s\n", mono_method_full_name (method, TRUE));
 
-       if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
-               cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
-
        dont_inline = g_list_prepend (dont_inline, method);
        if (cfg->method == method) {
 
+               if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
+                       cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
+
                /* ENTRY BLOCK */
                cfg->bb_entry = start_bblock = NEW_BBLOCK (cfg);
                start_bblock->cil_code = NULL;
@@ -2839,6 +2949,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        bblock = tblock;
                        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);                                                
                                NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
                                *sp++ = ins;
                        }
@@ -2852,13 +2964,17 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                bblock->next_bb = tblock;
                                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);                                                
                                        NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
                                        *sp++ = ins;
                                }
                        }
                }
 
-               if (cfg->coverage_info) {
+               bblock->real_offset = real_offset;
+
+               if ((cfg->method == method) && cfg->coverage_info) {
                        MonoInst *store, *one;
                        guint32 cil_offset = ip - header->code;
                        cfg->coverage_info->data [cil_offset].cil_code = ip;
@@ -2881,9 +2997,6 @@ 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));
 
-               /* Workaround for bug #51126 */
-               bblock->real_offset = real_offset;
-
                switch (*ip) {
                case CEE_NOP:
                        ++ip;
@@ -3060,7 +3173,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        *sp++ = ins;
                        break;
                case CEE_LDC_R4: {
-                       float *f = g_malloc (sizeof (float));
+                       float *f = mono_mempool_alloc (cfg->domain->mp, sizeof (float));
                        CHECK_OPSIZE (5);
                        CHECK_STACK_OVF (1);
                        MONO_INST_NEW (cfg, ins, OP_R4CONST);
@@ -3073,7 +3186,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        break;
                }
                case CEE_LDC_R8: {
-                       double *d = g_malloc (sizeof (double));
+                       double *d = mono_mempool_alloc (cfg->domain->mp, sizeof (double));
                        CHECK_OPSIZE (9);
                        CHECK_STACK_OVF (1);
                        MONO_INST_NEW (cfg, ins, OP_R8CONST);
@@ -3135,7 +3248,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 = mini_get_method (image, token, method);
+                       cmethod = mono_get_method_full (image, token, NULL, generic_context);
                        ins->inst_p0 = cmethod;
                        MONO_ADD_INS (bblock, ins);
                        ip += 5;
@@ -3166,24 +3279,20 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        } else {
                                if (method->wrapper_type != MONO_WRAPPER_NONE) {
                                        cmethod =  (MonoMethod *)mono_method_get_wrapper_data (method, token);
+                               } else if (constrained_call) {
+                                       cmethod = mono_get_method_constrained (image, token, constrained_call, generic_context);
                                } else {
-                                       cmethod = mini_get_method (image, token, method);
+                                       cmethod = mono_get_method_full (image, token, NULL, generic_context);
                                }
 
+                               g_assert (cmethod);
+
                                if (!cmethod->klass->inited)
                                        mono_class_init (cmethod->klass);
 
                                if (cmethod->signature->pinvoke) {
-#ifdef MONO_USE_EXC_TABLES
-                                       if (mono_method_blittable (cmethod)) {
-                                               fsig = cmethod->signature;
-                                       } else {
-#endif
                                                MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod);
                                                fsig = wrapper->signature;
-#ifdef MONO_USE_EXC_TABLES
-                                       }
-#endif
                                } else {
                                        fsig = mono_method_get_signature (cmethod, image, token);
                                }
@@ -3206,6 +3315,43 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                        sp -= n;
 
+                       if (constrained_call) {
+                               /*
+                                * We have the `constrained.' prefix opcode.
+                                */
+                               if (constrained_call->valuetype && !cmethod->klass->valuetype) {
+                                       MonoInst *load;
+                                       /*
+                                        * The type parameter is instantiated as a valuetype,
+                                        * but that type doesn't override the method we're
+                                        * calling, so we need to box `this'.
+                                        * sp [0] is a pointer to the data: we need the value
+                                        * in handle_box (), so load it here.
+                                        */
+                                       MONO_INST_NEW (cfg, load, mono_type_to_ldind (&constrained_call->byval_arg));
+                                       type_to_eval_stack_type (&constrained_call->byval_arg, load);
+                                       load->cil_code = ip;
+                                       load->inst_left = sp [0];
+                                       sp [0] = handle_box (cfg, bblock, load, ip, constrained_call);
+                               } else if (!constrained_call->valuetype) {
+                                       MonoInst *ins;
+
+                                       /*
+                                        * The type parameter is instantiated as a reference
+                                        * type.  We have a managed pointer on the stack, so
+                                        * we need to dereference it here.
+                                        */
+
+                                       MONO_INST_NEW (cfg, ins, CEE_LDIND_REF);
+                                       ins->cil_code = ip;
+                                       ins->inst_i0 = sp [0];
+                                       ins->type = STACK_OBJ;
+                                       sp [0] = ins;
+                               } else if (cmethod->klass->valuetype)
+                                       virtual = 0;
+                               constrained_call = NULL;
+                       }
+
                        if (*ip != CEE_CALLI && check_call_signature (cfg, fsig, sp))
                                goto unverified;
 
@@ -3260,11 +3406,18 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if ((cfg->opt & MONO_OPT_INLINE) && cmethod &&
                            (!virtual || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || (cmethod->flags & METHOD_ATTRIBUTE_FINAL)) && 
                            mono_method_check_inlining (cfg, cmethod) &&
-                           !g_list_find (dont_inline, cmethod)) {
+                                !g_list_find (dont_inline, cmethod)) {
                                int costs;
                                MonoBasicBlock *ebblock;
+                               gboolean allways = FALSE;
+
+                               if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
+                                       (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
+                                       cmethod = mono_marshal_get_native_wrapper (cmethod);
+                                       allways = TRUE;
+                               }
 
-                               if ((costs = inline_method (cfg, cmethod, fsig, bblock, sp, ip, real_offset, dont_inline, &ebblock))) {
+                               if ((costs = inline_method (cfg, cmethod, fsig, bblock, sp, ip, real_offset, dont_inline, &ebblock, allways))) {
                                        ip += 5;
                                        real_offset += 5;
 
@@ -3336,13 +3489,32 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
                                        if (sp [fsig->param_count]->type == STACK_OBJ) {
                                                MonoInst *iargs [2];
+                                               MonoInst *array, *to_store, *store;
 
                                                handle_loaded_temps (cfg, bblock, stack_start, sp);
                                                
-                                               iargs [0] = sp [0];
-                                               iargs [1] = sp [fsig->param_count];
-                       
-                                               mono_emit_jit_icall (cfg, bblock, helper_stelem_ref_check, iargs, ip);                                          
+                                               array = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
+                                               NEW_TEMPSTORE (cfg, store, array->inst_c0, sp [0]);
+                                               store->cil_code = ip;
+                                               MONO_ADD_INS (bblock, store);
+                                               NEW_TEMPLOAD (cfg, iargs [0], array->inst_c0);
+
+                                               to_store = mono_compile_create_var (cfg, type_from_stack_type (sp [fsig->param_count]), OP_LOCAL);
+                                               NEW_TEMPSTORE (cfg, store, to_store->inst_c0, sp [fsig->param_count]);
+                                               store->cil_code = ip;
+                                               MONO_ADD_INS (bblock, store);
+                                               NEW_TEMPLOAD (cfg, iargs [1], to_store->inst_c0);
+
+                                               /*
+                                                * We first save the args for the call so that the args are copied to the stack
+                                                * and a new instruction tree for them is created. If we don't do this,
+                                                * the same MonoInst is added to two different trees and this is not 
+                                                * allowed by burg.
+                                                */
+                                               mono_emit_jit_icall (cfg, bblock, helper_stelem_ref_check, iargs, ip);
+
+                                               NEW_TEMPLOAD (cfg, sp [0], array->inst_c0);
+                                               NEW_TEMPLOAD (cfg, sp [fsig->param_count], to_store->inst_c0);
                                        }
 
                                        addr = mini_get_ldelema_ins (cfg, bblock, cmethod, sp, ip, TRUE);
@@ -3627,17 +3799,20 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                case CEE_SHR_UN:
                        CHECK_STACK (2);
                        ADD_BINOP (*ip);
+                       /* special case that gives a nice speedup and happens to workaorund a ppc jit but (for the release)
+                        * later apply the speedup to the left shift as well
+                        * See BUG# 57957.
+                        */
+                       if ((ins->opcode == OP_LSHR_UN) && (ins->type == STACK_I8) 
+                                       && (ins->inst_right->opcode == OP_ICONST) && (ins->inst_right->inst_c0 == 32)) {
+                               ins->opcode = OP_LONG_SHRUN_32;
+                               /*g_print ("applied long shr speedup to %s\n", cfg->method->name);*/
+                               ip++;
+                               break;
+                       }
                        if (mono_find_jit_opcode_emulation (ins->opcode)) {
-                               MonoInst *store, *temp, *load;
                                --sp;
-                               temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
-                               NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
-                               store->cil_code = ins->cil_code;
-                               MONO_ADD_INS (bblock, store);
-                               NEW_TEMPLOAD (cfg, load, temp->inst_c0);
-                               load->cil_code = ins->cil_code;
-                               *sp++ = load;
-                               /*g_print ("found emulation for %d\n", ins->opcode);*/
+                               *sp++ = emit_tree (cfg, bblock, ins);
                        }
                        ip++;
                        break;
@@ -3657,16 +3832,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_STACK (1);
                        ADD_UNOP (*ip);
                        if (mono_find_jit_opcode_emulation (ins->opcode)) {
-                               MonoInst *store, *temp, *load;
                                --sp;
-                               temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
-                               NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
-                               store->cil_code = ins->cil_code;
-                               MONO_ADD_INS (bblock, store);
-                               NEW_TEMPLOAD (cfg, load, temp->inst_c0);
-                               load->cil_code = ins->cil_code;
-                               *sp++ = load;
-                               /*g_print ("found emulation for %d\n", ins->opcode);*/
+                               *sp++ = emit_tree (cfg, bblock, ins);
                        }
                        ip++;                   
                        break;
@@ -3721,13 +3888,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (method->wrapper_type != MONO_WRAPPER_NONE)
                                klass = mono_method_get_wrapper_data (method, token);
                        else
-                               klass = mono_class_get (image, token);
+                               klass = mono_class_get_full (image, token, generic_context);
 
                        mono_class_init (klass);
-                       if (klass->byval_arg.type == MONO_TYPE_VAR)
-                               klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
-                       else if (klass->byval_arg.type == MONO_TYPE_MVAR)
-                               klass = MTYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
                        sp -= 2;
                        if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
                                MonoInst *store, *load;
@@ -3775,13 +3938,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (method->wrapper_type != MONO_WRAPPER_NONE)
                                klass = mono_method_get_wrapper_data (method, token);
                        else
-                               klass = mono_class_get (image, token);
+                               klass = mono_class_get_full (image, token, generic_context);
 
                        mono_class_init (klass);
-                       if (klass->byval_arg.type == MONO_TYPE_VAR)
-                               klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
-                       else if (klass->byval_arg.type == MONO_TYPE_MVAR)
-                               klass = MTYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
                        if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
                                MONO_INST_NEW (cfg, ins, CEE_LDIND_REF);
                                ins->cil_code = ip;
@@ -3873,7 +4032,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 = mini_get_method (image, token, method);
+                               cmethod = mono_get_method_full (image, token, NULL, generic_context);
                        fsig = mono_method_get_signature (cmethod, image, token);
 
                        mono_class_init (cmethod->klass);
@@ -3892,7 +4051,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                        if (cmethod->klass->parent == mono_defaults.array_class) {
                                NEW_METHODCONST (cfg, *sp, cmethod);
-                               temp = mono_emit_native_call (cfg, bblock, mono_array_new_va, fsig, sp, ip, FALSE);
+                               temp = mono_emit_native_call (cfg, bblock, mono_array_new_va, mono_get_array_new_va_signature (fsig->param_count), sp, ip, FALSE);
+                               cfg->flags |= MONO_CFG_HAS_VARARGS;
 
                        } else if (cmethod->string_ctor) {
                                /* we simply pass a null pointer */
@@ -3927,7 +4087,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                    !g_list_find (dont_inline, cmethod)) {
                                        int costs;
                                        MonoBasicBlock *ebblock;
-                                       if ((costs = inline_method (cfg, cmethod, fsig, bblock, sp, ip, real_offset, dont_inline, &ebblock))) {
+                                       if ((costs = inline_method (cfg, cmethod, fsig, bblock, sp, ip, real_offset, dont_inline, &ebblock, FALSE))) {
 
                                                ip += 5;
                                                real_offset += 5;
@@ -3966,17 +4126,39 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_STACK (1);
                        --sp;
                        CHECK_OPSIZE (5);
-                       klass = mono_class_get (image, read32 (ip + 1));
+                       klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
                        mono_class_init (klass);
                
-                       if (klass->marshalbyref) {
-                               MonoInst *iargs [2];
-                               int temp;                       
-                               iargs [0] = *sp;
-                               NEW_CLASSCONST (cfg, iargs [1], klass);
-                               temp = mono_emit_native_call (cfg, bblock, mono_object_isinst_mbyref, helper_sig_obj_obj_cls, iargs, ip, FALSE);
+                       if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
+                       
+                               MonoMethod *mono_isinst;
+                               MonoInst *iargs [1];
+                               MonoBasicBlock *ebblock;
+                               int costs;
+                               int temp;
+                               
+                               mono_isinst = mono_marshal_get_isinst (klass); 
+                               iargs [0] = sp [0];
+                               
+                               costs = inline_method (cfg, mono_isinst, mono_isinst->signature, bblock, 
+                                                          iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
+                       
+                               g_assert (costs > 0);
+                               
+                               ip += 5;
+                               real_offset += 5;
+                       
+                               GET_BBLOCK (cfg, bbhash, bblock, ip);
+                               ebblock->next_bb = bblock;
+                               link_bblock (cfg, ebblock, bblock);
+
+                               temp = iargs [0]->inst_i0->inst_c0;
                                NEW_TEMPLOAD (cfg, *sp, temp);
-                               sp++;
+                               
+                               sp++;
+                               bblock = ebblock;
+                               inline_costs += costs;
+
                        }
                        else {
                                MONO_INST_NEW (cfg, ins, *ip);
@@ -3984,9 +4166,9 @@ 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++ = ins;
+                               *sp++ = emit_tree (cfg, bblock, ins);
+                               ip += 5;
                        }
-                       ip += 5;
                        break;
                case CEE_UNBOX_ANY: {
                        MonoInst *add, *vtoffset;
@@ -3999,24 +4181,39 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (method->wrapper_type != MONO_WRAPPER_NONE)
                                klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
                        else 
-                               klass = mono_class_get (image, token);
+                               klass = mono_class_get_full (image, token, generic_context);
                        mono_class_init (klass);
 
-                       if (klass->byval_arg.type == MONO_TYPE_VAR)
-                               klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
-                       else if (klass->byval_arg.type == MONO_TYPE_MVAR)
-                               klass = MTYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
-
                        if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
                                /* CASTCLASS */
-                               if (klass->marshalbyref) {
-                                       MonoInst *iargs [2];
+                               if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
+                                       MonoMethod *mono_castclass;
+                                       MonoInst *iargs [1];
+                                       MonoBasicBlock *ebblock;
+                                       int costs;
                                        int temp;
-                                       iargs [0] = *sp;
-                                       NEW_CLASSCONST (cfg, iargs [1], klass);
-                                       temp = mono_emit_jit_icall (cfg, bblock, mono_object_castclass_mbyref, iargs, ip);
+                                       
+                                       mono_castclass = mono_marshal_get_castclass (klass); 
+                                       iargs [0] = sp [0];
+                                       
+                                       costs = inline_method (cfg, mono_castclass, mono_castclass->signature, bblock, 
+                                                                  iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
+                               
+                                       g_assert (costs > 0);
+                                       
+                                       ip += 5;
+                                       real_offset += 5;
+                               
+                                       GET_BBLOCK (cfg, bbhash, bblock, ip);
+                                       ebblock->next_bb = bblock;
+                                       link_bblock (cfg, ebblock, bblock);
+       
+                                       temp = iargs [0]->inst_i0->inst_c0;
                                        NEW_TEMPLOAD (cfg, *sp, temp);
+                                       
                                        sp++;
+                                       bblock = ebblock;
+                                       inline_costs += costs;                          
                                }
                                else {
                                        MONO_INST_NEW (cfg, ins, CEE_CASTCLASS);
@@ -4038,7 +4235,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        ins->inst_newa_class = klass;
                        ins->cil_code = ip;
 
-                       MONO_INST_NEW (cfg, add, CEE_ADD);
+                       MONO_INST_NEW (cfg, add, OP_PADD);
                        NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
                        add->inst_left = ins;
                        add->inst_right = vtoffset;
@@ -4079,14 +4276,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (method->wrapper_type != MONO_WRAPPER_NONE)
                                klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
                        else 
-                               klass = mono_class_get (image, token);
+                               klass = mono_class_get_full (image, token, generic_context);
                        mono_class_init (klass);
 
-                       if (klass->byval_arg.type == MONO_TYPE_VAR)
-                               klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
-                       else if (klass->byval_arg.type == MONO_TYPE_MVAR)
-                               klass = MTYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
-
                        MONO_INST_NEW (cfg, ins, OP_UNBOXCAST);
                        ins->type = STACK_OBJ;
                        ins->inst_left = *sp;
@@ -4094,7 +4286,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        ins->inst_newa_class = klass;
                        ins->cil_code = ip;
 
-                       MONO_INST_NEW (cfg, add, CEE_ADD);
+                       MONO_INST_NEW (cfg, add, OP_PADD);
                        NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
                        add->inst_left = ins;
                        add->inst_right = vtoffset;
@@ -4108,21 +4300,38 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_STACK (1);
                        --sp;
                        CHECK_OPSIZE (5);
-                       klass = mono_class_get (image, read32 (ip + 1));
+                       klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
                        mono_class_init (klass);
-                       if (klass->byval_arg.type == MONO_TYPE_VAR)
-                               klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
-                       else if (klass->byval_arg.type == MONO_TYPE_MVAR)
-                               klass = MTYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
                
-                       if (klass->marshalbyref) {
-                               MonoInst *iargs [2];
+                       if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
+                               
+                               MonoMethod *mono_castclass;
+                               MonoInst *iargs [1];
+                               MonoBasicBlock *ebblock;
+                               int costs;
                                int temp;
-                               iargs [0] = *sp;
-                               NEW_CLASSCONST (cfg, iargs [1], klass);
-                               temp = mono_emit_jit_icall (cfg, bblock, mono_object_castclass_mbyref, iargs, ip);
+                               
+                               mono_castclass = mono_marshal_get_castclass (klass); 
+                               iargs [0] = sp [0];
+                               
+                               costs = inline_method (cfg, mono_castclass, mono_castclass->signature, bblock, 
+                                                          iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
+                       
+                               g_assert (costs > 0);
+                               
+                               ip += 5;
+                               real_offset += 5;
+                       
+                               GET_BBLOCK (cfg, bbhash, bblock, ip);
+                               ebblock->next_bb = bblock;
+                               link_bblock (cfg, ebblock, bblock);
+
+                               temp = iargs [0]->inst_i0->inst_c0;
                                NEW_TEMPLOAD (cfg, *sp, temp);
-                               sp++;
+                               
+                               sp++;
+                               bblock = ebblock;
+                               inline_costs += costs;
                        }
                        else {
                                MONO_INST_NEW (cfg, ins, *ip);
@@ -4131,9 +4340,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                ins->klass = klass;
                                ins->inst_newa_class = klass;
                                ins->cil_code = ip;
-                               *sp++ = ins;
+                               *sp++ = emit_tree (cfg, bblock, ins);
+                               ip += 5;
                        }
-                       ip += 5;
                        break;
                case CEE_THROW:
                        CHECK_STACK (1);
@@ -4166,17 +4375,13 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        //      goto unverified;
                        CHECK_OPSIZE (5);
                        token = read32 (ip + 1);
-                       field = mono_field_from_token (image, token, &klass);
-                       if (field->parent->gen_params)
-                               field = get_generic_field_inst (field, method->klass, &klass);
-                       else if (field->parent->generic_inst && method->klass->generic_inst)
-                               field = inflate_generic_field (field, method->klass, &klass);
+                       field = mono_field_from_token (image, token, &klass, generic_context);
                        mono_class_init (klass);
 
                        foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
                        /* FIXME: mark instructions for use in SSA */
                        if (*ip == CEE_STFLD) {
-                               if (klass->marshalbyref && !MONO_CHECK_THIS (sp [0])) {
+                               if ((klass->marshalbyref && !MONO_CHECK_THIS (sp [0])) || klass->contextbound) {
                                        MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
                                        MonoInst *iargs [5];
 
@@ -4189,7 +4394,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                                        if (cfg->opt & MONO_OPT_INLINE) {
                                                costs = inline_method (cfg, stfld_wrapper, stfld_wrapper->signature, bblock, 
-                                                                      iargs, ip, real_offset, dont_inline, &ebblock);
+                                                                      iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
                                                g_assert (costs > 0);
                                                      
                                                ip += 5;
@@ -4211,7 +4416,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                } else {
                                        MonoInst *store;
                                        NEW_ICONST (cfg, offset_ins, foffset);
-                                       MONO_INST_NEW (cfg, ins, CEE_ADD);
+                                       MONO_INST_NEW (cfg, ins, OP_PADD);
                                        ins->cil_code = ip;
                                        ins->inst_left = *sp;
                                        ins->inst_right = offset_ins;
@@ -4231,7 +4436,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                MONO_ADD_INS (bblock, store);
                                }
                        } else {
-                               if (klass->marshalbyref && !MONO_CHECK_THIS (sp [0])) {
+                               if ((klass->marshalbyref && !MONO_CHECK_THIS (sp [0])) || klass->contextbound) {
                                        /* fixme: we need to inline that call somehow */
                                        MonoMethod *ldfld_wrapper = mono_marshal_get_ldfld_wrapper (field->type); 
                                        MonoInst *iargs [4];
@@ -4243,7 +4448,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
                                        if (cfg->opt & MONO_OPT_INLINE) {
                                                costs = inline_method (cfg, ldfld_wrapper, ldfld_wrapper->signature, bblock, 
-                                                                      iargs, ip, real_offset, dont_inline, &ebblock);
+                                                                      iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
                                                g_assert (costs > 0);
                                                      
                                                ip += 5;
@@ -4281,7 +4486,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        }
                                } else {
                                        NEW_ICONST (cfg, offset_ins, foffset);
-                                       MONO_INST_NEW (cfg, ins, CEE_ADD);
+                                       MONO_INST_NEW (cfg, ins, OP_PADD);
                                        ins->cil_code = ip;
                                        ins->inst_left = *sp;
                                        ins->inst_right = offset_ins;
@@ -4313,14 +4518,11 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_OPSIZE (5);
                        token = read32 (ip + 1);
 
-                       field = mono_field_from_token (image, token, &klass);
-                       if (field->parent->gen_params)
-                               field = get_generic_field_inst (field, method->klass, &klass);
-                       else if (field->parent->generic_inst && method->klass->generic_inst)
-                               field = inflate_generic_field (field, method->klass, &klass);
+                       field = mono_field_from_token (image, token, &klass, generic_context);
                        mono_class_init (klass);
 
-                       handle_loaded_temps (cfg, bblock, stack_start, sp);
+                       if ((*ip) == CEE_STSFLD)
+                               handle_loaded_temps (cfg, bblock, stack_start, sp);
 
                        if (cfg->domain->special_static_fields)
                                addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
@@ -4477,12 +4679,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (method->wrapper_type != MONO_WRAPPER_NONE)
                                klass = mono_method_get_wrapper_data (method, token);
                        else
-                               klass = mono_class_get (image, token);
+                               klass = mono_class_get_full (image, token, generic_context);
                        mono_class_init (klass);
-                       if (klass->byval_arg.type == MONO_TYPE_VAR)
-                               klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
-                       else if (klass->byval_arg.type == MONO_TYPE_MVAR)
-                               klass = MTYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
                        n = mono_type_to_stind (&klass->byval_arg);
                        if (n == CEE_STOBJ) {
                                handle_stobj (cfg, bblock, sp [0], sp [1], ip, klass, FALSE, FALSE);
@@ -4501,9 +4699,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        inline_costs += 1;
                        break;
                case CEE_BOX: {
-                       MonoInst *iargs [2];
-                       MonoInst *load, *vtoffset, *add, *val, *vstore;
-                       int temp;
+                       MonoInst *val;
                        CHECK_STACK (1);
                        --sp;
                        val = *sp;
@@ -4512,52 +4708,15 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (method->wrapper_type != MONO_WRAPPER_NONE)
                                klass = mono_method_get_wrapper_data (method, token);
                        else
-                               klass = mono_class_get (image, token);
+                               klass = mono_class_get_full (image, token, generic_context);
                        mono_class_init (klass);
-                       if (klass->byval_arg.type == MONO_TYPE_VAR)
-                               klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
-                       else if (klass->byval_arg.type == MONO_TYPE_MVAR)
-                               klass = MTYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
 
                        if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
                                *sp++ = val;
                                ip += 5;
                                break;
                        }
-                       /* much like NEWOBJ */
-                       if (cfg->opt & MONO_OPT_SHARED) {
-                               NEW_DOMAINCONST (cfg, iargs [0]);
-                               NEW_CLASSCONST (cfg, iargs [1], klass);
-
-                               temp = mono_emit_jit_icall (cfg, bblock, mono_object_new, iargs, ip);
-                       } else {
-                               MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
-                               NEW_VTABLECONST (cfg, iargs [0], vtable);
-                               if (klass->has_finalize || (cfg->prof_options & MONO_PROFILE_ALLOCATIONS))
-                                       temp = mono_emit_jit_icall (cfg, bblock, mono_object_new_specific, iargs, ip);
-                               else
-                                       temp = mono_emit_jit_icall (cfg, bblock, mono_object_new_fast, iargs, ip);
-                       }
-                       NEW_TEMPLOAD (cfg, load, temp);
-                       NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
-                       MONO_INST_NEW (cfg, add, CEE_ADD);
-                       add->inst_left = load;
-                       add->inst_right = vtoffset;
-                       add->cil_code = ip;
-                       add->klass = klass;
-                       MONO_INST_NEW (cfg, vstore, CEE_STIND_I);
-                       vstore->opcode = mono_type_to_stind (&klass->byval_arg);
-                       vstore->cil_code = ip;
-                       vstore->inst_left = add;
-                       vstore->inst_right = val;
-
-                       if (vstore->opcode == CEE_STOBJ) {
-                               handle_stobj (cfg, bblock, add, val, ip, klass, FALSE, FALSE);
-                       } else
-                               MONO_ADD_INS (bblock, vstore);
-
-                       NEW_TEMPLOAD (cfg, load, temp);
-                       *sp++ = load;
+                       *sp++ = handle_box (cfg, bblock, val, ip, klass);
                        ip += 5;
                        inline_costs += 1;
                        break;
@@ -4578,13 +4737,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (method->wrapper_type != MONO_WRAPPER_NONE)
                                klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
                        else
-                               klass = mono_class_get (image, token);
+                               klass = mono_class_get_full (image, token, generic_context);
 
                        mono_class_init (klass);
-                       if (klass->byval_arg.type == MONO_TYPE_VAR)
-                               klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
-                       else if (klass->byval_arg.type == MONO_TYPE_MVAR)
-                               klass = MTYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
                        ins->inst_newa_class = klass;
                        ins->inst_newa_len = *sp;
                        ins->type = STACK_OBJ;
@@ -4624,29 +4779,21 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (method->wrapper_type != MONO_WRAPPER_NONE)
                                klass = (MonoClass*)mono_method_get_wrapper_data (method, read32 (ip + 1));
                        else
-                               klass = mono_class_get (image, read32 (ip + 1));
+                               klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
                        mono_class_init (klass);
-                       if (klass->byval_arg.type == MONO_TYPE_VAR)
-                               klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
-                       else if (klass->byval_arg.type == MONO_TYPE_MVAR)
-                               klass = MTYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
                        NEW_LDELEMA (cfg, ins, sp, klass);
                        ins->cil_code = ip;
                        *sp++ = ins;
                        ip += 5;
                        break;
-               case CEE_LDELEM: {
+               case CEE_LDELEM_ANY: {
                        MonoInst *load;
                        CHECK_STACK (2);
                        sp -= 2;
                        CHECK_OPSIZE (5);
                        token = read32 (ip + 1);
-                       klass = mono_class_get (image, token);
+                       klass = mono_class_get_full (image, token, generic_context);
                        mono_class_init (klass);
-                       if (klass->byval_arg.type == MONO_TYPE_VAR)
-                               klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
-                       else if (klass->byval_arg.type == MONO_TYPE_MVAR)
-                               klass = MTYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
                        NEW_LDELEMA (cfg, load, sp, klass);
                        load->cil_code = ip;
                        MONO_INST_NEW (cfg, ins, mono_type_to_ldind (&klass->byval_arg));
@@ -4715,7 +4862,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        inline_costs += 1;
                        break;
                }
-               case CEE_STELEM: {
+               case CEE_STELEM_ANY: {
                        MonoInst *load;
                        /*
                         * translate to:
@@ -4726,30 +4873,33 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        sp -= 3;
                        CHECK_OPSIZE (5);
                        token = read32 (ip + 1);
-                       klass = mono_class_get (image, token);
+                       klass = mono_class_get_full (image, token, generic_context);
                        mono_class_init (klass);
-                       if (klass->byval_arg.type == MONO_TYPE_VAR)
-                               klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
-                       else if (klass->byval_arg.type == MONO_TYPE_MVAR)
-                               klass = MTYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
                        if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
+                               MonoMethod* helper = mono_marshal_get_stelemref ();
                                MonoInst *iargs [3];
                                handle_loaded_temps (cfg, bblock, stack_start, sp);
 
                                iargs [2] = sp [2];
                                iargs [1] = sp [1];
                                iargs [0] = sp [0];
-                       
-                               mono_emit_jit_icall (cfg, bblock, helper_stelem_ref, iargs, ip);
+                               
+                               mono_emit_method_call_spilled (cfg, bblock, helper, helper->signature, iargs, ip, NULL);
                        } else {
                                NEW_LDELEMA (cfg, load, sp, klass);
                                load->cil_code = ip;
-                               MONO_INST_NEW (cfg, ins, mono_type_to_stind (&klass->byval_arg));
-                               ins->cil_code = ip;
-                               ins->inst_left = load;
-                               ins->inst_right = sp [2];
-                               handle_loaded_temps (cfg, bblock, stack_start, sp);
-                               MONO_ADD_INS (bblock, ins);
+
+                               n = mono_type_to_stind (&klass->byval_arg);
+                               if (n == CEE_STOBJ)
+                                       handle_stobj (cfg, bblock, load, sp [2], ip, klass, FALSE, FALSE);
+                               else {
+                                       MONO_INST_NEW (cfg, ins, n);
+                                       ins->cil_code = ip;
+                                       ins->inst_left = load;
+                                       ins->inst_right = sp [2];
+                                       handle_loaded_temps (cfg, bblock, stack_start, sp);
+                                       MONO_ADD_INS (bblock, ins);
+                               }
                        }
                        ip += 5;
                        inline_costs += 1;
@@ -4757,6 +4907,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                }
                case CEE_STELEM_REF: {
                        MonoInst *iargs [3];
+                       MonoMethod* helper = mono_marshal_get_stelemref ();
 
                        CHECK_STACK (3);
                        sp -= 3;
@@ -4767,7 +4918,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        iargs [1] = sp [1];
                        iargs [0] = sp [0];
                        
-                       mono_emit_jit_icall (cfg, bblock, helper_stelem_ref, iargs, ip);
+                       mono_emit_method_call_spilled (cfg, bblock, helper, helper->signature, iargs, ip, NULL);
 
                        /*
                        MonoInst *group;
@@ -4812,12 +4963,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        MONO_INST_NEW (cfg, ins, *ip);
                        --sp;
                        CHECK_OPSIZE (5);
-                       klass = mono_class_get (image, read32 (ip + 1));
+                       klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
                        mono_class_init (klass);
-                       if (klass->byval_arg.type == MONO_TYPE_VAR)
-                               klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
-                       else if (klass->byval_arg.type == MONO_TYPE_MVAR)
-                               klass = MTYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
                        ins->type = STACK_MP;
                        ins->inst_left = *sp;
                        ins->klass = klass;
@@ -4833,12 +4980,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        MONO_INST_NEW (cfg, ins, *ip);
                        --sp;
                        CHECK_OPSIZE (5);
-                       klass = mono_class_get (image, read32 (ip + 1));
+                       klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
                        mono_class_init (klass);
-                       if (klass->byval_arg.type == MONO_TYPE_VAR)
-                               klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
-                       else if (klass->byval_arg.type == MONO_TYPE_MVAR)
-                               klass = MTYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
                        ins->cil_code = ip;
 
                        loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
@@ -4863,7 +5006,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_OPSIZE (5);
                        n = read32 (ip + 1);
 
-                       handle = mono_ldtoken (image, n, &handle_class);
+                       handle = mono_ldtoken (image, n, &handle_class, generic_context);
                        mono_class_init (handle_class);
 
                        if (cfg->opt & MONO_OPT_SHARED) {
@@ -4881,9 +5024,11 @@ 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 = mini_get_method (image, read32 (ip + 6), method)) &&
+                               if ((ip [5] == CEE_CALL) && (cmethod = mono_get_method_full (image, read32 (ip + 6), NULL, generic_context)) &&
                                                (cmethod->klass == mono_defaults.monotype_class->parent) &&
-                                               (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
+                                               (strcmp (cmethod->name, "GetTypeFromHandle") == 0) && 
+                                       ((g_hash_table_lookup (bbhash, ip + 5) == NULL) ||
+                                        (g_hash_table_lookup (bbhash, ip + 5) == bblock))) {
                                        MonoClass *tclass = mono_class_from_mono_type (handle);
                                        mono_class_init (tclass);
                                        if (mono_compile_aot)
@@ -4894,12 +5039,17 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        ins->klass = cmethod->klass;
                                        ip += 5;
                                } else {
+                                       MonoInst *store, *addr, *vtvar;
+
                                        if (mono_compile_aot)
                                                NEW_LDTOKENCONST (cfg, ins, image, n);
                                        else
                                                NEW_PCONST (cfg, ins, handle);
-                                       ins->type = STACK_VTYPE;
-                                       ins->klass = handle_class;
+                                       vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
+                                       NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
+                                       NEW_INDSTORE (cfg, store, addr, ins, &mono_defaults.int_class->byval_arg);
+                                       MONO_ADD_INS (bblock, store);
+                                       NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
                                }
                        }
 
@@ -4922,14 +5072,29 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                case CEE_SUB_OVF_UN:
                        CHECK_STACK (2);
                        ADD_BINOP (*ip);
+                       if (mono_find_jit_opcode_emulation (ins->opcode)) {
+                               --sp;
+                               *sp++ = emit_tree (cfg, bblock, ins);
+                       }
                        ip++;
                        break;
                case CEE_ENDFINALLY:
-                       /* FIXME: check stack state */
                        MONO_INST_NEW (cfg, ins, *ip);
                        MONO_ADD_INS (bblock, ins);
                        ins->cil_code = ip++;
                        start_new_bblock = 1;
+
+                       /*
+                        * Control will leave the method so empty the stack, otherwise
+                        * the next basic block will start with a nonempty stack.
+                        */
+                       while (sp != stack_start) {
+                               MONO_INST_NEW (cfg, ins, CEE_POP);
+                               ins->cil_code = ip;
+                               sp--;
+                               ins->inst_i0 = *sp;
+                               MONO_ADD_INS (bblock, ins);
+                       }
                        break;
                case CEE_LEAVE:
                case CEE_LEAVE_S: {
@@ -5025,121 +5190,30 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_OPSIZE (2);
                        switch (ip [1]) {
 
-                       case CEE_MONO_FUNC1: {
+                       case CEE_MONO_ICALL: {
                                int temp;
-                               gpointer func = NULL;
-                               CHECK_STACK (1);
-                               sp--;
+                               gpointer func;
+                               MonoJitICallInfo *info;
 
-                               CHECK_OPSIZE (3);
-                               switch (ip [2]) {
-                               case MONO_MARSHAL_CONV_STR_LPWSTR:
-                                       func = mono_string_to_utf16;
-                                       break;
-                               case MONO_MARSHAL_CONV_LPWSTR_STR:
-                                       func = mono_string_from_utf16;
-                                       break;
-                               case MONO_MARSHAL_CONV_LPSTR_STR:
-                                       func = mono_string_new_wrapper;
-                                       break;
-                               case MONO_MARSHAL_CONV_STR_LPTSTR:
-                               case MONO_MARSHAL_CONV_STR_LPSTR:
-                                       func = mono_string_to_utf8;
-                                       break;
-                               case MONO_MARSHAL_CONV_STR_BSTR:
-                                       func = mono_string_to_bstr;
-                                       break;
-                               case MONO_MARSHAL_CONV_STR_TBSTR:
-                               case MONO_MARSHAL_CONV_STR_ANSIBSTR:
-                                       func = mono_string_to_ansibstr;
-                                       break;
-                               case MONO_MARSHAL_CONV_SB_LPSTR:
-                               case MONO_MARSHAL_CONV_SB_LPTSTR:
-                                       func = mono_string_builder_to_utf8;
-                                       break;
-                               case MONO_MARSHAL_CONV_SB_LPWSTR:
-                                       func = mono_string_builder_to_utf16;
-                                       break;
-                               case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY:
-                                       func = mono_array_to_savearray;
-                                       break;
-                               case MONO_MARSHAL_CONV_ARRAY_LPARRAY:
-                                       func = mono_array_to_lparray;
-                                       break;
-                               case MONO_MARSHAL_CONV_DEL_FTN:
-                                       func = mono_delegate_to_ftnptr;
-                                       break;
-                               case MONO_MARSHAL_CONV_STRARRAY_STRLPARRAY:
-                                       func = mono_marshal_string_array;
-                                       break;
-                               default:
-                                       g_warning ("unknown conversion %d\n", ip [2]);
-                                       g_assert_not_reached ();
-                               }
-
-                               temp = mono_emit_jit_icall (cfg, bblock, func, sp, ip);
-                               NEW_TEMPLOAD (cfg, *sp, temp);
-                               sp++;
+                               token = read32 (ip + 2);
+                               func = mono_method_get_wrapper_data (method, token);
+                               info = mono_find_jit_icall_by_addr (func);
+                               g_assert (info);
 
-                               ip += 3;
-                               inline_costs += 10 * num_calls++;
-                               break;
-                       }
-                       case CEE_MONO_PROC2: {
-                               gpointer func = NULL;
-                               CHECK_STACK (2);
-                               sp -= 2;
+                               CHECK_STACK (info->sig->param_count);
+                               sp -= info->sig->param_count;
 
-                               CHECK_OPSIZE (3);
-                               switch (ip [2]) {
-                               case MONO_MARSHAL_CONV_LPSTR_SB:
-                               case MONO_MARSHAL_CONV_LPTSTR_SB:
-                                       func = mono_string_utf8_to_builder;
-                                       break;
-                               case MONO_MARSHAL_CONV_LPWSTR_SB:
-                                       func = mono_string_utf16_to_builder;
-                                       break;
-                               case MONO_MARSHAL_FREE_ARRAY:
-                                       func = mono_marshal_free_array;
-                                       break;
-                               default:
-                                       g_assert_not_reached ();
+                               temp = mono_emit_jit_icall (cfg, bblock, info->func, sp, ip);
+                               if (!MONO_TYPE_IS_VOID (info->sig->ret)) {
+                                       NEW_TEMPLOAD (cfg, *sp, temp);
+                                       sp++;
                                }
 
-                               mono_emit_jit_icall (cfg, bblock, func, sp, ip);
-                               ip += 3;
+                               ip += 6;
                                inline_costs += 10 * num_calls++;
-                               break;
-                       }
-                       case CEE_MONO_PROC3: {
-                               gpointer func = NULL;
-                               CHECK_STACK (3);
-                               sp -= 3;
-
-                               CHECK_OPSIZE (3);
-                               switch (ip [2]) {
-                               case MONO_MARSHAL_CONV_STR_BYVALSTR:
-                                       func = mono_string_to_byvalstr;
-                                       break;
-                               case MONO_MARSHAL_CONV_STR_BYVALWSTR:
-                                       func = mono_string_to_byvalwstr;
-                                       break;
-                               default:
-                                       g_assert_not_reached ();
-                               }
 
-                               mono_emit_jit_icall (cfg, bblock, func, sp, ip);
-                               ip += 3;
-                               inline_costs += 10 * num_calls++;
                                break;
                        }
-                       case CEE_MONO_FREE:
-                               CHECK_STACK (1);
-                               sp -= 1;
-                               mono_emit_jit_icall (cfg, bblock, g_free, sp, ip);
-                               ip += 2;
-                               inline_costs += 10 * num_calls++;
-                               break;
                        case CEE_MONO_LDPTR:
                                CHECK_STACK_OVF (1);
                                CHECK_OPSIZE (6);
@@ -5222,6 +5296,32 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                start_new_bblock = 1;
                                ip += 6;
                                break;
+                       case CEE_MONO_CISINST:
+                       case CEE_MONO_CCASTCLASS: {
+                               int token;
+                               CHECK_STACK (1);
+                               --sp;
+                               CHECK_OPSIZE (6);
+                               token = read32 (ip + 2);
+                               klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
+                               MONO_INST_NEW (cfg, ins, (ip [1] == CEE_MONO_CISINST) ? OP_CISINST : OP_CCASTCLASS);
+                               ins->type = STACK_I4;
+                               ins->inst_left = *sp;
+                               ins->inst_newa_class = klass;
+                               ins->cil_code = ip;
+                               *sp++ = emit_tree (cfg, bblock, ins);
+                               ip += 6;
+                               break;
+                       }
+                       case CEE_MONO_SAVE_LMF:
+                       case CEE_MONO_RESTORE_LMF:
+#ifdef MONO_ARCH_HAVE_LMF_OPS
+                               MONO_INST_NEW (cfg, ins, (ip [1] == CEE_MONO_SAVE_LMF) ? OP_SAVE_LMF : OP_RESTORE_LMF);
+                               MONO_ADD_INS (bblock, ins);
+                               cfg->need_lmf_area = TRUE;
+#endif
+                               ip += 2;
+                               break;
                        default:
                                g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
                                break;
@@ -5273,11 +5373,21 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                cmp->cil_code = ip;
                                type_from_op (cmp);
                                CHECK_TYPE (cmp);
-                               cmp->opcode = OP_COMPARE;
+                               if ((sp [0]->type == STACK_I8) || ((sizeof (gpointer) == 8) && ((sp [0]->type == STACK_PTR) || (sp [0]->type == STACK_OBJ) || (sp [0]->type == STACK_MP))))
+                                       cmp->opcode = OP_LCOMPARE;
+                               else
+                                       cmp->opcode = OP_COMPARE;
                                ins->cil_code = ip;
                                ins->type = STACK_I4;
                                ins->inst_i0 = cmp;
                                *sp++ = ins;
+                               /* spill it to reduce the expression complexity
+                                * and workaround bug 54209 
+                                */
+                               if (cmp->inst_left->type == STACK_I8) {
+                                       --sp;
+                                       *sp++ = emit_tree (cfg, bblock, ins);
+                               }
                                ip += 2;
                                break;
                        }
@@ -5291,7 +5401,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 = mini_get_method (image, n, method);
+                                       cmethod = mono_get_method_full (image, n, NULL, generic_context);
                                }
 
                                mono_class_init (cmethod->klass);
@@ -5319,7 +5429,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 = mini_get_method (image, n, method);
+                                       cmethod = mono_get_method_full (image, n, NULL, generic_context);
 
                                mono_class_init (cmethod->klass);
                                handle_loaded_temps (cfg, bblock, stack_start, sp);
@@ -5416,6 +5526,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
                                ins->inst_left = *sp;
                                ins->cil_code = ip;
+                               ins->type = STACK_MP;
 
                                cfg->flags |= MONO_CFG_HAS_ALLOCA;
                                if (header->init_locals)
@@ -5466,7 +5577,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                ip += 2;
                                break;
                        case CEE_TAIL_:
-                               ins_flag |= MONO_INST_TAILCALL;
+                               ins_flag   |= MONO_INST_TAILCALL;
+                               cfg->flags |= MONO_CFG_HAS_TAIL;
                                /* Can't inline tail calls at this time */
                                inline_costs += 100000;
                                ip += 2;
@@ -5479,12 +5591,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                if (method->wrapper_type != MONO_WRAPPER_NONE)
                                        klass = mono_method_get_wrapper_data (method, token);
                                else
-                                       klass = mono_class_get (image, token);
-                               if (klass->byval_arg.type == MONO_TYPE_VAR)
-                                       klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
-                               else if (klass->byval_arg.type == MONO_TYPE_MVAR)
-                                       klass = MTYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
-
+                                       klass = mono_class_get_full (image, token, generic_context);
                                if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
                                        MonoInst *store, *load;
                                        NEW_PCONST (cfg, load, NULL);
@@ -5506,6 +5613,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                /* FIXME: implement */
                                CHECK_OPSIZE (6);
                                token = read32 (ip + 2);
+                               constrained_call = mono_class_get_full (image, token, generic_context);
                                ip += 6;
                                break;
                        case CEE_CPBLK:
@@ -5513,6 +5621,17 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                MonoInst *iargs [3];
                                CHECK_STACK (3);
                                sp -= 3;
+                               if ((cfg->opt & MONO_OPT_INTRINS) && (ip [1] == CEE_CPBLK) && (sp [2]->opcode == OP_ICONST) && ((n = sp [2]->inst_c0) <= sizeof (gpointer) * 5)) {
+                                       MonoInst *copy;
+                                       MONO_INST_NEW (cfg, copy, OP_MEMCPY);
+                                       copy->inst_left = sp [0];
+                                       copy->inst_right = sp [1];
+                                       copy->cil_code = ip;
+                                       copy->unused = n;
+                                       MONO_ADD_INS (bblock, copy);
+                                       ip += 2;
+                                       break;
+                               }
                                iargs [0] = sp [0];
                                iargs [1] = sp [1];
                                iargs [2] = sp [2];
@@ -5560,7 +5679,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        MonoType *type = mono_type_create_from_typespec (image, token);
                                        token = mono_type_size (type, &align);
                                } else {
-                                       MonoClass *szclass = mono_class_get (image, token);
+                                       MonoClass *szclass = mono_class_get_full (image, token, generic_context);
                                        mono_class_init (szclass);
                                        token = mono_class_value_size (szclass, &align);
                                }
@@ -5571,7 +5690,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                break;
                        case CEE_REFANYTYPE:
                                CHECK_STACK (1);
-                               MONO_INST_NEW (cfg, ins, ip [1]);
+                               MONO_INST_NEW (cfg, ins, OP_REFANYTYPE);
                                --sp;
                                ins->type = STACK_MP;
                                ins->inst_left = *sp;
@@ -5729,7 +5848,10 @@ mono_print_tree (MonoInst *tree) {
                printf ("[%d]", tree->inst_c0);
                break;
        case OP_REGOFFSET:
-               printf ("[0x%x(%s)]", tree->inst_offset, mono_arch_regname (tree->inst_basereg));
+               if (tree->inst_offset < 0)
+                       printf ("[-0x%x(%s)]", -tree->inst_offset, mono_arch_regname (tree->inst_basereg));
+               else
+                       printf ("[0x%x(%s)]", tree->inst_offset, mono_arch_regname (tree->inst_basereg));
                break;
        case OP_REGVAR:
                printf ("[%s]", mono_arch_regname (tree->dreg));
@@ -5807,10 +5929,12 @@ mono_print_tree (MonoInst *tree) {
                mono_print_tree (tree->inst_left);
                break;
        default:
-               if (arity) {
-                       mono_print_tree (tree->inst_left);
-                       if (arity > 1)
-                               mono_print_tree (tree->inst_right);
+               if (!mono_arch_print_tree(tree, arity)) {
+                       if (arity) {
+                               mono_print_tree (tree->inst_left);
+                               if (arity > 1)
+                                       mono_print_tree (tree->inst_right);
+                       }
                }
                break;
        }
@@ -5826,246 +5950,125 @@ mono_print_tree_nl (MonoInst *tree)
        printf ("\n");
 }
 
+#define make_icall_sig mono_create_icall_signature
+
 static void
 create_helper_signature (void)
 {
-       /* FIXME: set call conv */
        /* MonoArray * mono_array_new (MonoDomain *domain, MonoClass *klass, gint32 len) */
-       helper_sig_newarr = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
-       helper_sig_newarr->params [0] = helper_sig_newarr->params [1] = &mono_defaults.int_class->byval_arg;
-       helper_sig_newarr->ret = &mono_defaults.object_class->byval_arg;
-       helper_sig_newarr->params [2] = &mono_defaults.int32_class->byval_arg;
-       helper_sig_newarr->pinvoke = 1;
+       helper_sig_newarr = make_icall_sig ("object ptr ptr int32");
 
        /* MonoArray * mono_array_new_specific (MonoVTable *vtable, guint32 len) */
-       helper_sig_newarr_specific = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
-       helper_sig_newarr_specific->params [0] = &mono_defaults.int_class->byval_arg;
-       helper_sig_newarr_specific->params [1] = &mono_defaults.int32_class->byval_arg;
-       helper_sig_newarr_specific->ret = &mono_defaults.object_class->byval_arg;
-       helper_sig_newarr_specific->pinvoke = 1;
+       helper_sig_newarr_specific = make_icall_sig ("object ptr int32");
 
        /* MonoObject * mono_object_new (MonoDomain *domain, MonoClass *klass) */
-       helper_sig_object_new = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
-       helper_sig_object_new->params [0] = helper_sig_object_new->params [1] = &mono_defaults.int_class->byval_arg;
-       helper_sig_object_new->ret = &mono_defaults.object_class->byval_arg;
-       helper_sig_object_new->pinvoke = 1;
+       helper_sig_object_new = make_icall_sig ("object ptr ptr");
 
        /* MonoObject * mono_object_new_specific (MonoVTable *vtable) */
-       helper_sig_object_new_specific = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
-       helper_sig_object_new_specific->params [0] = &mono_defaults.int_class->byval_arg;
-       helper_sig_object_new_specific->ret = &mono_defaults.object_class->byval_arg;
-       helper_sig_object_new_specific->pinvoke = 1;
+       helper_sig_object_new_specific = make_icall_sig ("object ptr");
 
        /* void* mono_method_compile (MonoMethod*) */
-       helper_sig_compile = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
-       helper_sig_compile->params [0] = helper_sig_compile->ret = &mono_defaults.int_class->byval_arg;
-       helper_sig_compile->pinvoke = 1;
+       helper_sig_compile = make_icall_sig ("ptr ptr");
 
        /* void* mono_ldvirtfn (MonoObject *, MonoMethod*) */
-       helper_sig_compile_virt = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
-       helper_sig_compile_virt->params [0] = &mono_defaults.object_class->byval_arg;
-       helper_sig_compile_virt->params [1] = helper_sig_compile_virt->ret = &mono_defaults.int_class->byval_arg;
-       helper_sig_compile_virt->pinvoke = 1;
+       helper_sig_compile_virt = make_icall_sig ("ptr object ptr");
 
        /* MonoString* mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 str_index) */
-       helper_sig_ldstr = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
-       helper_sig_ldstr->params [0] = helper_sig_ldstr->params [1] = &mono_defaults.int_class->byval_arg;
-       helper_sig_ldstr->params [2] = &mono_defaults.int32_class->byval_arg;
-       helper_sig_ldstr->ret = &mono_defaults.object_class->byval_arg;
-       helper_sig_ldstr->pinvoke = 1;
+       helper_sig_ldstr = make_icall_sig ("object ptr ptr int32");
 
        /* MonoDomain *mono_domain_get (void) */
-       helper_sig_domain_get = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
-       helper_sig_domain_get->ret = &mono_defaults.int_class->byval_arg;
-       helper_sig_domain_get->pinvoke = 1;
-
-       /* void* stelem_ref (MonoArray *, int index, MonoObject *) */
-       helper_sig_stelem_ref = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
-       helper_sig_stelem_ref->params [0] = &mono_defaults.array_class->byval_arg;
-       helper_sig_stelem_ref->params [1] = &mono_defaults.int32_class->byval_arg;
-       helper_sig_stelem_ref->params [2] = &mono_defaults.object_class->byval_arg;
-       helper_sig_stelem_ref->ret = &mono_defaults.void_class->byval_arg;
-       helper_sig_stelem_ref->pinvoke = 1;
-
-       /* void* stelem_ref_check (MonoArray *, MonoObject *) */
-       helper_sig_stelem_ref_check = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
-       helper_sig_stelem_ref_check->params [0] = &mono_defaults.array_class->byval_arg;
-       helper_sig_stelem_ref_check->params [1] = &mono_defaults.object_class->byval_arg;
-       helper_sig_stelem_ref_check->ret = &mono_defaults.void_class->byval_arg;
-       helper_sig_stelem_ref_check->pinvoke = 1;
+       helper_sig_domain_get = make_icall_sig ("ptr");
+
+       /* void stelem_ref (MonoArray *, int index, MonoObject *) */
+       helper_sig_stelem_ref = make_icall_sig ("void ptr int32 object");
+
+       /* void stelem_ref_check (MonoArray *, MonoObject *) */
+       helper_sig_stelem_ref_check = make_icall_sig ("void object object");
 
        /* long amethod (long, long) */
-       helper_sig_long_long_long = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
-       helper_sig_long_long_long->params [0] = helper_sig_long_long_long->params [1] = 
-               &mono_defaults.int64_class->byval_arg;
-       helper_sig_long_long_long->ret = &mono_defaults.int64_class->byval_arg;
-       helper_sig_long_long_long->pinvoke = 1;
+       helper_sig_long_long_long = make_icall_sig ("long long long");
 
        /* object  amethod (intptr) */
-       helper_sig_obj_ptr = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
-       helper_sig_obj_ptr->params [0] = &mono_defaults.int_class->byval_arg;
-       helper_sig_obj_ptr->ret = &mono_defaults.object_class->byval_arg;
-       helper_sig_obj_ptr->pinvoke = 1;
+       helper_sig_obj_ptr = make_icall_sig ("object ptr");
+
+       helper_sig_obj_ptr_ptr = make_icall_sig ("object ptr ptr");
+
+       helper_sig_obj_obj_ptr_ptr = make_icall_sig ("object object ptr ptr");
+
+       helper_sig_void_void = make_icall_sig ("void");
 
        /* void amethod (intptr) */
-       helper_sig_void_ptr = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
-       helper_sig_void_ptr->params [0] = &mono_defaults.int_class->byval_arg;
-       helper_sig_void_ptr->ret = &mono_defaults.void_class->byval_arg;
-       helper_sig_void_ptr->pinvoke = 1;
+       helper_sig_void_ptr = make_icall_sig ("void ptr");
 
        /* void amethod (MonoObject *obj) */
-       helper_sig_void_obj = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
-       helper_sig_void_obj->params [0] = &mono_defaults.object_class->byval_arg;
-       helper_sig_void_obj->ret = &mono_defaults.void_class->byval_arg;
-       helper_sig_void_obj->pinvoke = 1;
+       helper_sig_void_obj = make_icall_sig ("void object");
+
+       /* void amethod (MonoObject *obj, void *ptr, int i) */
+       helper_sig_void_obj_ptr_int = make_icall_sig ("void object ptr int");
+
+       helper_sig_void_obj_ptr_ptr_obj = make_icall_sig ("void object ptr ptr object");
 
        /* intptr amethod (void) */
-       helper_sig_ptr_void = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
-       helper_sig_ptr_void->ret = &mono_defaults.int_class->byval_arg;
-       helper_sig_ptr_void->pinvoke = 1;
+       helper_sig_ptr_void = make_icall_sig ("ptr");
 
        /* object amethod (void) */
-       helper_sig_obj_void = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
-       helper_sig_obj_void->ret = &mono_defaults.object_class->byval_arg;
-       helper_sig_obj_void->pinvoke = 1;
+       helper_sig_obj_void = make_icall_sig ("object");
 
        /* void  amethod (intptr, intptr) */
-       helper_sig_void_ptr_ptr = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
-       helper_sig_void_ptr_ptr->params [0] = &mono_defaults.int_class->byval_arg;
-       helper_sig_void_ptr_ptr->params [1] = &mono_defaults.int_class->byval_arg;
-       helper_sig_void_ptr_ptr->ret = &mono_defaults.void_class->byval_arg;
-       helper_sig_void_ptr_ptr->pinvoke = 1;
+       helper_sig_void_ptr_ptr = make_icall_sig ("void ptr ptr");
 
        /* void  amethod (intptr, intptr, intptr) */
-       helper_sig_void_ptr_ptr_ptr = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
-       helper_sig_void_ptr_ptr_ptr->params [0] = &mono_defaults.int_class->byval_arg;
-       helper_sig_void_ptr_ptr_ptr->params [1] = &mono_defaults.int_class->byval_arg;
-       helper_sig_void_ptr_ptr_ptr->params [2] = &mono_defaults.int_class->byval_arg;
-       helper_sig_void_ptr_ptr_ptr->ret = &mono_defaults.void_class->byval_arg;
-       helper_sig_void_ptr_ptr_ptr->pinvoke = 1;
+       helper_sig_void_ptr_ptr_ptr = make_icall_sig ("void ptr ptr ptr");
 
        /* intptr  amethod (intptr, intptr) */
-       helper_sig_ptr_ptr_ptr = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
-       helper_sig_ptr_ptr_ptr->params [0] = &mono_defaults.int_class->byval_arg;
-       helper_sig_ptr_ptr_ptr->params [1] = &mono_defaults.int_class->byval_arg;
-       helper_sig_ptr_ptr_ptr->ret = &mono_defaults.int_class->byval_arg;
-       helper_sig_ptr_ptr_ptr->pinvoke = 1;
+       helper_sig_ptr_ptr_ptr = make_icall_sig ("ptr ptr ptr");
 
        /* IntPtr  amethod (object) */
-       helper_sig_ptr_obj = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
-       helper_sig_ptr_obj->params [0] = &mono_defaults.object_class->byval_arg;
-       helper_sig_ptr_obj->ret = &mono_defaults.int_class->byval_arg;
-       helper_sig_ptr_obj->pinvoke = 1;
+       helper_sig_ptr_obj = make_icall_sig ("ptr object");
+
+       /* IntPtr  amethod (object, int) */
+       helper_sig_ptr_obj_int = make_icall_sig ("ptr object int");
 
        /* IntPtr  amethod (int) */
-       helper_sig_ptr_int = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
-       helper_sig_ptr_int->params [0] = &mono_defaults.int32_class->byval_arg;
-       helper_sig_ptr_int->ret = &mono_defaults.int_class->byval_arg;
-       helper_sig_ptr_int->pinvoke = 1;
+       helper_sig_ptr_int = make_icall_sig ("ptr int32");
 
        /* long amethod (long, guint32) */
-       helper_sig_long_long_int = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
-       helper_sig_long_long_int->params [0] = &mono_defaults.int64_class->byval_arg;
-       helper_sig_long_long_int->params [1] = &mono_defaults.int32_class->byval_arg;
-       helper_sig_long_long_int->ret = &mono_defaults.int64_class->byval_arg;
-       helper_sig_long_long_int->pinvoke = 1;
+       helper_sig_long_long_int = make_icall_sig ("long long int32");
 
        /* ulong amethod (double) */
-       helper_sig_ulong_double = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
-       helper_sig_ulong_double->params [0] = &mono_defaults.double_class->byval_arg;
-       helper_sig_ulong_double->ret = &mono_defaults.uint64_class->byval_arg;
-       helper_sig_ulong_double->pinvoke = 1;
+       helper_sig_ulong_double = make_icall_sig ("ulong double");
 
        /* long amethod (double) */
-       helper_sig_long_double = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
-       helper_sig_long_double->params [0] = &mono_defaults.double_class->byval_arg;
-       helper_sig_long_double->ret = &mono_defaults.int64_class->byval_arg;
-       helper_sig_long_double->pinvoke = 1;
+       helper_sig_long_double = make_icall_sig ("long double");
 
        /* double amethod (long) */
-       helper_sig_double_long = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
-       helper_sig_double_long->params [0] = &mono_defaults.int64_class->byval_arg;
-       helper_sig_double_long->ret = &mono_defaults.double_class->byval_arg;
-       helper_sig_double_long->pinvoke = 1;
+       helper_sig_double_long = make_icall_sig ("double long");
+
+       /* double amethod (int) */
+       helper_sig_double_int = make_icall_sig ("double int32");
 
        /* float amethod (long) */
-       helper_sig_float_long = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
-       helper_sig_float_long->params [0] = &mono_defaults.int64_class->byval_arg;
-       helper_sig_float_long->ret = &mono_defaults.single_class->byval_arg;
-       helper_sig_float_long->pinvoke = 1;
+       helper_sig_float_long = make_icall_sig ("float long");
 
        /* double amethod (double, double) */
-       helper_sig_double_double_double = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
-       helper_sig_double_double_double->params [0] = &mono_defaults.double_class->byval_arg;
-       helper_sig_double_double_double->params [1] = &mono_defaults.double_class->byval_arg;
-       helper_sig_double_double_double->ret = &mono_defaults.double_class->byval_arg;
-       helper_sig_double_double_double->pinvoke = 1;
+       helper_sig_double_double_double = make_icall_sig ("double double double");
 
        /* uint amethod (double) */
-       helper_sig_uint_double = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
-       helper_sig_uint_double->params [0] = &mono_defaults.double_class->byval_arg;
-       helper_sig_uint_double->ret = &mono_defaults.uint32_class->byval_arg;
-       helper_sig_uint_double->pinvoke = 1;
+       helper_sig_uint_double = make_icall_sig ("uint32 double");
 
        /* int amethod (double) */
-       helper_sig_int_double = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
-       helper_sig_int_double->params [0] = &mono_defaults.double_class->byval_arg;
-       helper_sig_int_double->ret = &mono_defaults.int32_class->byval_arg;
-       helper_sig_int_double->pinvoke = 1;
+       helper_sig_int_double = make_icall_sig ("int32 double");
 
        /* void  initobj (intptr, int size) */
-       helper_sig_initobj = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
-       helper_sig_initobj->params [0] = &mono_defaults.int_class->byval_arg;
-       helper_sig_initobj->params [1] = &mono_defaults.int32_class->byval_arg;
-       helper_sig_initobj->ret = &mono_defaults.void_class->byval_arg;
-       helper_sig_initobj->pinvoke = 1;
+       helper_sig_initobj = make_icall_sig ("void ptr int32");
 
        /* void  memcpy (intptr, intptr, int size) */
-       helper_sig_memcpy = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
-       helper_sig_memcpy->params [0] = &mono_defaults.int_class->byval_arg;
-       helper_sig_memcpy->params [1] = &mono_defaults.int_class->byval_arg;
-       helper_sig_memcpy->params [2] = &mono_defaults.int32_class->byval_arg;
-       helper_sig_memcpy->ret = &mono_defaults.void_class->byval_arg;
-       helper_sig_memcpy->pinvoke = 1;
+       helper_sig_memcpy = make_icall_sig ("void ptr ptr int32");
 
        /* void  memset (intptr, int val, int size) */
-       helper_sig_memset = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
-       helper_sig_memset->params [0] = &mono_defaults.int_class->byval_arg;
-       helper_sig_memset->params [1] = &mono_defaults.int32_class->byval_arg;
-       helper_sig_memset->params [2] = &mono_defaults.int32_class->byval_arg;
-       helper_sig_memset->ret = &mono_defaults.void_class->byval_arg;
-       helper_sig_memset->pinvoke = 1;
-
-       helper_sig_class_init_trampoline = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
-       helper_sig_class_init_trampoline->ret = &mono_defaults.void_class->byval_arg;
-       helper_sig_class_init_trampoline->pinvoke = 1;  
-       
-       /* MonoObject * amethod (MonoObject *obj, MonoClass *klass) */
-       helper_sig_obj_obj_cls = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
-       helper_sig_obj_obj_cls->params [0] = &mono_defaults.object_class->byval_arg;
-       helper_sig_obj_obj_cls->params [1] = &mono_defaults.int_class->byval_arg;
-       helper_sig_obj_obj_cls->ret = &mono_defaults.object_class->byval_arg;
-       helper_sig_obj_obj_cls->pinvoke = 1;
-}
-
-static GHashTable *jit_icall_hash_name = NULL;
-static GHashTable *jit_icall_hash_addr = NULL;
+       helper_sig_memset = make_icall_sig ("void ptr int32 int32");
 
-MonoJitICallInfo *
-mono_find_jit_icall_by_name (const char *name)
-{
-       g_assert (jit_icall_hash_name);
-
-       //printf ("lookup addr %s %p\n", name, g_hash_table_lookup (jit_icall_hash_name, name));
-       return g_hash_table_lookup (jit_icall_hash_name, name);
-}
-
-MonoJitICallInfo *
-mono_find_jit_icall_by_addr (gconstpointer addr)
-{
-       g_assert (jit_icall_hash_addr);
-
-       return g_hash_table_lookup (jit_icall_hash_addr, (gpointer)addr);
+       helper_sig_class_init_trampoline = make_icall_sig ("void");
 }
 
 gconstpointer
@@ -6073,60 +6076,26 @@ mono_icall_get_wrapper (MonoJitICallInfo* callinfo)
 {
        char *name;
        MonoMethod *wrapper;
+       gconstpointer code;
        
        if (callinfo->wrapper)
                return callinfo->wrapper;
+       
        name = g_strdup_printf ("__icall_wrapper_%s", callinfo->name);
        wrapper = mono_marshal_get_icall_wrapper (callinfo->sig, name, callinfo->func);
        /* Must be domain neutral since there is only one copy */
-       callinfo->wrapper = mono_jit_compile_method_with_opt (wrapper, default_opt | MONO_OPT_SHARED);
+       code = mono_jit_compile_method_with_opt (wrapper, default_opt | MONO_OPT_SHARED);
 
-       g_hash_table_insert (jit_icall_hash_addr, (gpointer)callinfo->wrapper, callinfo);
+       if (!callinfo->wrapper) {
+               callinfo->wrapper = code;
+               mono_register_jit_icall_wrapper (callinfo, code);
+               mono_debug_add_icall_wrapper (wrapper, callinfo);
+       }
 
        g_free (name);
        return callinfo->wrapper;
 }
 
-MonoJitICallInfo *
-mono_register_jit_icall (gconstpointer func, const char *name, MonoMethodSignature *sig, gboolean is_save)
-{
-       MonoJitICallInfo *info;
-       
-       g_assert (func);
-       g_assert (name);
-
-       if (!jit_icall_hash_name) {
-               jit_icall_hash_name = g_hash_table_new (g_str_hash, g_str_equal);
-               jit_icall_hash_addr = g_hash_table_new (NULL, NULL);
-       }
-
-       if (g_hash_table_lookup (jit_icall_hash_name, name)) {
-               g_warning ("jit icall already defined \"%s\"\n", name);
-               g_assert_not_reached ();
-       }
-
-       info = g_new (MonoJitICallInfo, 1);
-       
-       info->name = name;
-       info->func = func;
-       info->sig = sig;
-
-       if (is_save
-#ifdef MONO_USE_EXC_TABLES
-           || mono_arch_has_unwind_info (func)
-#endif
-           ) {
-               info->wrapper = func;
-       } else {
-               info->wrapper = NULL;
-       }
-
-       g_hash_table_insert (jit_icall_hash_name, (gpointer)info->name, info);
-       g_hash_table_insert (jit_icall_hash_addr, (gpointer)func, info);
-
-       return info;
-}
-
 gpointer
 mono_create_class_init_trampoline (MonoVTable *vtable)
 {
@@ -6189,7 +6158,7 @@ mono_create_jump_trampoline (MonoDomain *domain, MonoMethod *method,
         * trampoline address, so we save it here.
         */
 
-       mono_jit_info_table_add (mono_root_domain, ji);
+       mono_jit_info_table_add (mono_get_root_domain (), ji);
 
        if (!jump_trampoline_hash)
                jump_trampoline_hash = g_hash_table_new (NULL, NULL);
@@ -6320,7 +6289,7 @@ print_dfn (MonoCompile *cfg) {
 
        for (i = 0; i < cfg->num_bblocks; ++i) {
                bb = cfg->bblocks [i];
-               if (bb->cil_code) {
+               /*if (bb->cil_code) {
                        char* code1, *code2;
                        code1 = mono_disasm_code_one (NULL, cfg->method, bb->cil_code, NULL);
                        if (bb->last_ins->cil_code)
@@ -6332,7 +6301,7 @@ print_dfn (MonoCompile *cfg) {
                        code = g_strdup_printf ("%s -> %s", code1, code2);
                        g_free (code1);
                        g_free (code2);
-               } else
+               } else*/
                        code = g_strdup ("\n");
                g_print ("\nBB%d DFN%d (len: %d): %s", bb->block_num, i, bb->cil_length, code);
                if (bb->code) {
@@ -6387,6 +6356,7 @@ mono_destroy_compile (MonoCompile *cfg)
 {
        //mono_mempool_stats (cfg->mempool);
        g_hash_table_destroy (cfg->bb_hash);
+       mono_free_loop_info (cfg);
        if (cfg->rs)
                mono_regstate_free (cfg->rs);
        if (cfg->spvars)
@@ -6399,9 +6369,16 @@ mono_destroy_compile (MonoCompile *cfg)
        g_free (cfg);
 }
 
+#ifdef HAVE_KW_THREAD
+static __thread gpointer mono_lmf_addr;
+#endif
+
 MonoLMF **
 mono_get_lmf_addr (void)
 {
+#ifdef HAVE_KW_THREAD
+       return mono_lmf_addr;
+#else
        MonoJitTlsData *jit_tls;
 
        if ((jit_tls = TlsGetValue (mono_jit_tls_id)))
@@ -6409,6 +6386,7 @@ mono_get_lmf_addr (void)
 
        g_assert_not_reached ();
        return NULL;
+#endif
 }
 
 /**
@@ -6434,6 +6412,10 @@ setup_jit_tls_data (gpointer stack_start, gpointer abort_func)
        MonoJitTlsData *jit_tls;
        MonoLMF *lmf;
 
+       jit_tls = TlsGetValue (mono_jit_tls_id);
+       if (jit_tls)
+               return jit_tls;
+
        jit_tls = g_new0 (MonoJitTlsData, 1);
 
        TlsSetValue (mono_jit_tls_id, jit_tls);
@@ -6446,6 +6428,10 @@ setup_jit_tls_data (gpointer stack_start, gpointer abort_func)
 
        jit_tls->lmf = jit_tls->first_lmf = lmf;
 
+#ifdef HAVE_KW_THREAD
+       mono_lmf_addr = &jit_tls->lmf;
+#endif
+
        mono_arch_setup_jit_tls_data (jit_tls);
 
        return jit_tls;
@@ -6521,6 +6507,144 @@ mono_remove_patch_info (MonoCompile *cfg, int ip)
        }
 }
 
+gpointer
+mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *patch_info, gboolean run_cctors)
+{
+       unsigned char *ip = patch_info->ip.i + code;
+       gconstpointer target = NULL;
+
+       switch (patch_info->type) {
+       case MONO_PATCH_INFO_BB:
+               target = patch_info->data.bb->native_offset + code;
+               break;
+       case MONO_PATCH_INFO_ABS:
+               target = patch_info->data.target;
+               break;
+       case MONO_PATCH_INFO_LABEL:
+               target = patch_info->data.inst->inst_c0 + code;
+               break;
+       case MONO_PATCH_INFO_IP:
+               target = ip;
+               break;
+       case MONO_PATCH_INFO_METHOD_REL:
+               target = code + patch_info->data.offset;
+               break;
+       case MONO_PATCH_INFO_INTERNAL_METHOD: {
+               MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name);
+               if (!mi) {
+                       g_warning ("unknown MONO_PATCH_INFO_INTERNAL_METHOD %s", patch_info->data.name);
+                       g_assert_not_reached ();
+               }
+               target = mono_icall_get_wrapper (mi);
+               break;
+       }
+       case MONO_PATCH_INFO_METHOD_JUMP: {
+               GSList *list;
+
+               /* get the trampoline to the method from the domain */
+               target = mono_create_jump_trampoline (domain, patch_info->data.method, TRUE);
+               if (!domain->jump_target_hash)
+                       domain->jump_target_hash = g_hash_table_new (NULL, NULL);
+               list = g_hash_table_lookup (domain->jump_target_hash, patch_info->data.method);
+               list = g_slist_prepend (list, ip);
+               g_hash_table_insert (domain->jump_target_hash, patch_info->data.method, list);
+               break;
+       }
+       case MONO_PATCH_INFO_METHOD:
+               if (patch_info->data.method == method) {
+                       target = code;
+               } else
+                       /* get the trampoline to the method from the domain */
+                       target = mono_arch_create_jit_trampoline (patch_info->data.method);
+               break;
+       case MONO_PATCH_INFO_SWITCH: {
+               gpointer *jump_table;
+               int i;
+       
+               mono_domain_lock (domain);
+               jump_table = mono_code_manager_reserve (domain->code_mp, sizeof (gpointer) * patch_info->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];
+               }
+               target = jump_table;
+               break;
+       }
+       case MONO_PATCH_INFO_METHODCONST:
+       case MONO_PATCH_INFO_CLASS:
+       case MONO_PATCH_INFO_IMAGE:
+       case MONO_PATCH_INFO_FIELD:
+               target = patch_info->data.target;
+               break;
+       case MONO_PATCH_INFO_IID:
+               mono_class_init (patch_info->data.klass);
+               target = (gpointer)patch_info->data.klass->interface_id;
+               break;
+       case MONO_PATCH_INFO_VTABLE:
+               target = mono_class_vtable (domain, patch_info->data.klass);
+               break;
+       case MONO_PATCH_INFO_CLASS_INIT:
+               target = mono_create_class_init_trampoline (mono_class_vtable (domain, patch_info->data.klass));
+               break;
+       case MONO_PATCH_INFO_SFLDA: {
+               MonoVTable *vtable = mono_class_vtable (domain, patch_info->data.field->parent);
+               if (!vtable->initialized && !(vtable->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) && mono_class_needs_cctor_run (vtable->klass, method))
+                       /* Done by the generated code */
+                       ;
+               else {
+                       if (run_cctors)
+                               mono_runtime_class_init (vtable);
+               }
+               target = (char*)vtable->data + patch_info->data.field->offset;
+               break;
+       }
+       case MONO_PATCH_INFO_R4:
+       case MONO_PATCH_INFO_R8:
+               target = patch_info->data.target;
+               break;
+       case MONO_PATCH_INFO_EXC_NAME:
+               target = patch_info->data.name;
+               break;
+       case MONO_PATCH_INFO_LDSTR:
+               target =
+                       mono_ldstr (domain, patch_info->data.token->image, 
+                                               mono_metadata_token_index (patch_info->data.token->token));
+               break;
+       case MONO_PATCH_INFO_TYPE_FROM_HANDLE: {
+               gpointer handle;
+               MonoClass *handle_class;
+
+               handle = mono_ldtoken (patch_info->data.token->image, 
+                                      patch_info->data.token->token, &handle_class, NULL);
+               mono_class_init (handle_class);
+               mono_class_init (mono_class_from_mono_type (handle));
+
+               target =
+                       mono_type_get_object (domain, handle);
+               break;
+       }
+       case MONO_PATCH_INFO_LDTOKEN: {
+               gpointer handle;
+               MonoClass *handle_class;
+               
+               handle = mono_ldtoken (patch_info->data.token->image,
+                                      patch_info->data.token->token, &handle_class, NULL);
+               mono_class_init (handle_class);
+               
+               target = handle;
+               break;
+       }
+       case MONO_PATCH_INFO_BB_OVF:
+       case MONO_PATCH_INFO_EXC_OVF:
+               break;
+       default:
+               g_assert_not_reached ();
+       }
+
+       return (gpointer)target;
+}
+
 static void
 dec_foreach (MonoInst *tree, MonoCompile *cfg) {
        MonoJitICallInfo *info;
@@ -6551,7 +6675,8 @@ dec_foreach (MonoInst *tree, MonoCompile *cfg) {
                                && tree->inst_left->inst_left->type == STACK_I4
                                && (tree->inst_right->opcode == CEE_CONV_I8 
                                        || tree->inst_right->opcode == CEE_CONV_U8)
-                               && tree->inst_right->inst_left->type == STACK_I4) {
+                               && tree->inst_right->inst_left->type == STACK_I4
+                               && tree->inst_left->opcode == tree->inst_right->opcode) {
                        tree->opcode = (tree->inst_left->opcode == CEE_CONV_I8 ? OP_BIGMUL: OP_BIGMUL_UN);
                        tree->inst_left = tree->inst_left->inst_left;
                        tree->inst_right = tree->inst_right->inst_left;
@@ -6729,7 +6854,7 @@ optimize_branches (MonoCompile *cfg)
                                bbn = bb->out_bb [0];
 
                                /* 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 (bb->last_ins->opcode)) {
+                               if (bb->last_ins && MONO_IS_COND_BRANCH_OP (bb->last_ins)) {
                                        bb->last_ins->opcode = CEE_BR;
                                        bb->last_ins->inst_target_bb = bb->last_ins->inst_true_bb;
                                        changed = TRUE;
@@ -6800,17 +6925,19 @@ optimize_branches (MonoCompile *cfg)
                                            bbn->code->inst_target_bb->region == bb->region) {
                                                
                                                if (cfg->verbose_level > 2)
-                                                       g_print ("in %s branch to branch triggered %d -> %d\n", cfg->method->name, 
-                                                                bb->block_num, bbn->block_num);
-                                               
-                                               replace_basic_block (bb, bb->out_bb [0], bbn->code->inst_target_bb);
+                                                       g_print ("in %s branch to branch triggered %d -> %d -> %d\n", cfg->method->name, 
+                                                                bb->block_num, bbn->block_num, bbn->code->inst_target_bb->block_num);
+
+                                               replace_in_block (bbn, bb, NULL);
+                                               replace_out_block (bb, bbn, bbn->code->inst_target_bb);
+                                               link_bblock (cfg, bb, bbn->code->inst_target_bb);
                                                bb->last_ins->inst_target_bb = bbn->code->inst_target_bb;
                                                changed = TRUE;
                                                break;
                                        }
                                }
                        } else if (bb->out_count == 2) {
-                               if (bb->last_ins && MONO_IS_COND_BRANCH (bb->last_ins->opcode)) {
+                               if (bb->last_ins && MONO_IS_COND_BRANCH_NOFP (bb->last_ins)) {
                                        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) {
@@ -6971,18 +7098,22 @@ emit_state (MonoCompile *cfg, MBState *state, int goal)
 static void 
 mini_select_instructions (MonoCompile *cfg)
 {
-       static int reverse_map [] = {
+       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 int reverse_fmap [] = {
+       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 int reverse_lmap [] = {
+       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;
        
@@ -6990,10 +7121,13 @@ mini_select_instructions (MonoCompile *cfg)
        cfg->rs = mono_regstate_new ();
 
        for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
-               if (bb->last_ins && MONO_IS_COND_BRANCH (bb->last_ins->opcode) &&
+               if (bb->last_ins && MONO_IS_COND_BRANCH_OP (bb->last_ins) &&
                    bb->next_bb != bb->last_ins->inst_false_bb) {
 
-                       if (bb->next_bb ==  bb->last_ins->inst_true_bb) {
+                       /* we are careful when inverting, since bugs like #59580
+                        * could show up when dealing with NaNs.
+                        */
+                       if (MONO_IS_COND_BRANCH_NOFP(bb->last_ins) && bb->next_bb == bb->last_ins->inst_true_bb) {
                                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;
@@ -7004,6 +7138,8 @@ mini_select_instructions (MonoCompile *cfg)
                                        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];
                                }
                        } else {                        
                                MonoInst *inst = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst));
@@ -7115,7 +7251,11 @@ mono_codegen (MonoCompile *cfg)
        /* we always allocate code in cfg->domain->code_mp to increase locality */
        cfg->code_size = cfg->code_len + max_epilog_size;
        /* fixme: align to MONO_ARCH_CODE_ALIGNMENT */
+
+       mono_domain_lock (cfg->domain);
        code = mono_code_manager_reserve (cfg->domain->code_mp, cfg->code_size);
+       mono_domain_unlock (cfg->domain);
+
        memcpy (code, cfg->native_code, cfg->code_len);
        g_free (cfg->native_code);
        cfg->native_code = code;
@@ -7160,7 +7300,11 @@ mono_codegen (MonoCompile *cfg)
                        break;
                }
                case MONO_PATCH_INFO_SWITCH: {
-                       gpointer *table = mono_code_manager_reserve (cfg->domain->code_mp, sizeof (gpointer) * patch_info->table_size);
+                       gpointer *table;
+                       mono_domain_lock (cfg->domain);
+                       table = mono_code_manager_reserve (cfg->domain->code_mp, sizeof (gpointer) * patch_info->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;
@@ -7181,7 +7325,10 @@ mono_codegen (MonoCompile *cfg)
 
        mono_arch_patch_code (cfg->method, cfg->domain, cfg->native_code, cfg->patch_info, cfg->run_cctors);
 
+       mono_domain_lock (cfg->domain);
        mono_code_manager_commit (cfg->domain->code_mp, cfg->native_code, cfg->code_size, cfg->code_len);
+       mono_domain_unlock (cfg->domain);
+       
        mono_arch_flush_icache (cfg->native_code, cfg->code_len);
 
        mono_debug_close_method (cfg);
@@ -7476,7 +7623,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)) {
+       if (cfg->opt & (MONO_OPT_DEADCE | MONO_OPT_ABCREM)) {
                if (!(cfg->comp_done & MONO_COMP_SSA) && !header->num_clauses && !cfg->disable_ssa) {
                        mono_local_cprop (cfg);
                        mono_ssa_compute (cfg);
@@ -7505,6 +7652,9 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
 
                //mono_ssa_strength_reduction (cfg);
 
+               if ((cfg->flags & MONO_CFG_HAS_LDELEMA) && (cfg->opt & MONO_OPT_ABCREM))
+                       mono_perform_abc_removal (cfg);
+
                mono_ssa_remove (cfg);
 
                if (cfg->opt & MONO_OPT_BRANCH)
@@ -7621,40 +7771,30 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
 }
 
 static gpointer
-mono_jit_compile_method_inner (MonoMethod *method)
+mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain)
 {
-       /* FIXME: later copy the code from mono */
-       MonoDomain *target_domain, *domain = mono_domain_get ();
        MonoCompile *cfg;
        GHashTable *jit_code_hash;
-       gpointer code;
+       gpointer code = NULL;
        guint32 opt;
+       MonoJitInfo *info;
 
        opt = default_opt;
 
-       if (opt & MONO_OPT_SHARED)
-               target_domain = mono_root_domain;
-       else 
-               target_domain = domain;
-
        jit_code_hash = target_domain->jit_code_hash;
 
 #ifdef MONO_USE_AOT_COMPILER
        if (!mono_compile_aot && (opt & MONO_OPT_AOT)) {
                MonoJitInfo *info;
+               MonoDomain *domain = mono_domain_get ();
 
                mono_domain_lock (domain);
 
                mono_class_init (method->klass);
                if ((info = mono_aot_get_method (domain, method))) {
-
                        g_hash_table_insert (domain->jit_code_hash, method, info);
-
                        mono_domain_unlock (domain);
-
-                       /* make sure runtime_init is called */
                        mono_runtime_class_init (mono_class_vtable (domain, method->klass));
-
                        return info->code_start;
                }
 
@@ -7673,19 +7813,11 @@ mono_jit_compile_method_inner (MonoMethod *method)
                                if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
                                        mono_lookup_pinvoke_call (method, NULL, NULL);
                }
-#ifdef MONO_USE_EXC_TABLES
-               if (mono_method_blittable (method)) {
-                       return method->addr;
-               } else {
-#endif
                        nm = mono_marshal_get_native_wrapper (method);
                        return mono_compile_method (nm);
 
                        //if (mono_debug_format != MONO_DEBUG_FORMAT_NONE) 
                        //mono_debug_add_wrapper (method, nm);
-#ifdef MONO_USE_EXC_TABLES
-               }
-#endif
        } else if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
                const char *name = method->name;
                MonoMethod *nm;
@@ -7709,9 +7841,24 @@ mono_jit_compile_method_inner (MonoMethod *method)
        }
 
        cfg = mini_method_compile (method, opt, target_domain, TRUE, 0);
-       code = cfg->native_code;
 
-       g_hash_table_insert (jit_code_hash, method, cfg->jit_info);
+       mono_domain_lock (target_domain);
+
+       /* Check if some other thread already did the job. In this case, we can
+       discard the code this thread generated. */
+
+       if ((info = g_hash_table_lookup (target_domain->jit_code_hash, method))) {
+               /* We can't use a domain specific method in another domain */
+               if ((target_domain == mono_domain_get ()) || info->domain_neutral) {
+                       code = info->code_start;
+//                     printf("Discarding code for method %s\n", method->name);
+               }
+       }
+       
+       if (code == NULL) {
+               g_hash_table_insert (jit_code_hash, method, cfg->jit_info);
+               code = cfg->native_code;
+       }
 
        mono_destroy_compile (cfg);
 
@@ -7730,9 +7877,10 @@ mono_jit_compile_method_inner (MonoMethod *method)
                        mono_arch_patch_code (NULL, target_domain, tmp->data, &patch_info, TRUE);
                g_slist_free (list);
        }
-       /* make sure runtime_init is called */
-       mono_runtime_class_init (mono_class_vtable (target_domain, method->klass));
 
+       mono_domain_unlock (target_domain);
+
+       mono_runtime_class_init (mono_class_vtable (target_domain, method->klass));
        return code;
 }
 
@@ -7742,10 +7890,10 @@ mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt)
        /* FIXME: later copy the code from mono */
        MonoDomain *target_domain, *domain = mono_domain_get ();
        MonoJitInfo *info;
-       gpointer code;
+       gpointer p;
 
-       if (default_opt & MONO_OPT_SHARED)
-               target_domain = mono_root_domain;
+       if (opt & MONO_OPT_SHARED)
+               target_domain = mono_get_root_domain ();
        else 
                target_domain = domain;
 
@@ -7756,15 +7904,14 @@ mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt)
                if (! ((domain != target_domain) && !info->domain_neutral)) {
                        mono_domain_unlock (target_domain);
                        mono_jit_stats.methods_lookups++;
+                       mono_runtime_class_init (mono_class_vtable (domain, method->klass));
                        return info->code_start;
                }
        }
 
-       code = mono_jit_compile_method_inner (method);
-
        mono_domain_unlock (target_domain);
-
-       return code;
+       p = mono_jit_compile_method_inner (method, target_domain);
+       return p;
 }
 
 static gpointer
@@ -7780,7 +7927,7 @@ mono_jit_find_compiled_method (MonoDomain *domain, MonoMethod *method)
        MonoJitInfo *info;
 
        if (default_opt & MONO_OPT_SHARED)
-               target_domain = mono_root_domain;
+               target_domain = mono_get_root_domain ();
        else 
                target_domain = domain;
 
@@ -7811,7 +7958,8 @@ static MonoObject*
 mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
 {
        MonoMethod *invoke;
-       MonoObject *(*runtime_invoke) (MonoObject *this, void **params, MonoObject **exc);
+       MonoObject *(*runtime_invoke) (MonoObject *this, void **params, MonoObject **exc, void* compiled_method);
+       void* compiled_method;
 
        if (obj == NULL && !(method->flags & METHOD_ATTRIBUTE_STATIC) && !method->string_ctor && (method->wrapper_type == 0)) {
                g_warning ("Ignoring invocation of an instance method on a NULL instance.\n");
@@ -7820,20 +7968,45 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec
 
        invoke = mono_marshal_get_runtime_invoke (method);
        runtime_invoke = mono_jit_compile_method (invoke);
-       return runtime_invoke (obj, params, exc);
+       
+       /* We need this here becuase mono_marshal_get_runtime_invoke can be place 
+        * the helper method in System.Object and not the target class
+        */
+       mono_runtime_class_init (mono_class_vtable (mono_domain_get (), method->klass));
+
+       compiled_method = mono_jit_compile_method (method);
+       return runtime_invoke (obj, params, exc, compiled_method);
 }
 
 #ifdef PLATFORM_WIN32
 #define GET_CONTEXT \
        struct sigcontext *ctx = (struct sigcontext*)_dummy;
 #else
+#ifdef __sparc
+#define GET_CONTEXT \
+    void *ctx = context;
+#elif defined(sun)    // Solaris x86
+#define GET_CONTEXT \
+    ucontext_t *uctx = context; \
+    struct sigcontext *ctx = (struct sigcontext *)&(uctx->uc_mcontext);
+#elif defined(__ppc__) || defined (__powerpc__) || defined (__s390__) || defined (MONO_ARCH_USE_SIGACTION)
+#define GET_CONTEXT \
+    void *ctx = context;
+#else
 #define GET_CONTEXT \
        void **_p = (void **)&_dummy; \
        struct sigcontext *ctx = (struct sigcontext *)++_p;
 #endif
+#endif
+
+#ifdef MONO_ARCH_USE_SIGACTION
+#define SIG_HANDLER_SIGNATURE(ftn) ftn (int _dummy, siginfo_t *info, void *context)
+#else
+#define SIG_HANDLER_SIGNATURE(ftn) ftn (int _dummy)
+#endif
 
 static void
-sigfpe_signal_handler (int _dummy)
+SIG_HANDLER_SIGNATURE (sigfpe_signal_handler)
 {
        MonoException *exc;
        GET_CONTEXT
@@ -7844,7 +8017,7 @@ sigfpe_signal_handler (int _dummy)
 }
 
 static void
-sigill_signal_handler (int _dummy)
+SIG_HANDLER_SIGNATURE (sigill_signal_handler)
 {
        MonoException *exc;
        GET_CONTEXT
@@ -7861,7 +8034,7 @@ sigsegv_signal_handler (int _dummy, siginfo_t *info, void *context)
        MonoException *exc;
        MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
        struct sigcontext *ctx = (struct sigcontext *)&(((ucontext_t*)context)->uc_mcontext);
-
+               
        /* Can't allocate memory using Boehm GC on altstack */
        if (jit_tls->stack_size && 
                ((guint8*)info->si_addr >= (guint8*)jit_tls->end_of_stack - jit_tls->stack_size) &&
@@ -7876,7 +8049,7 @@ sigsegv_signal_handler (int _dummy, siginfo_t *info, void *context)
 #else
 
 static void
-sigsegv_signal_handler (int _dummy )
+SIG_HANDLER_SIGNATURE (sigsegv_signal_handler)
 {
        GET_CONTEXT;
 
@@ -7886,20 +8059,23 @@ sigsegv_signal_handler (int _dummy )
 #endif
 
 static void
-sigusr1_signal_handler (int _dummy)
+SIG_HANDLER_SIGNATURE (sigusr1_signal_handler)
 {
-       MonoThread *thread;
-       GET_CONTEXT
+       gboolean running_managed;
+       MonoException *exc;
        
-       thread = mono_thread_current ();
-
-       thread->abort_exc = mono_get_exception_thread_abort ();        
+       GET_CONTEXT
 
-       mono_arch_handle_exception (ctx, thread->abort_exc, FALSE);
+       running_managed = (mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context(ctx)) != NULL);
+       
+       exc = mono_thread_request_interruption (running_managed); 
+       if (!exc) return;
+       
+       mono_arch_handle_exception (ctx, exc, FALSE);
 }
 
 static void
-sigquit_signal_handler (int _dummy)
+SIG_HANDLER_SIGNATURE (sigquit_signal_handler)
 {
        MonoException *exc;
        GET_CONTEXT
@@ -7910,7 +8086,7 @@ sigquit_signal_handler (int _dummy)
 }
 
 static void
-sigint_signal_handler (int _dummy)
+SIG_HANDLER_SIGNATURE (sigint_signal_handler)
 {
        MonoException *exc;
        GET_CONTEXT
@@ -7920,10 +8096,29 @@ sigint_signal_handler (int _dummy)
        mono_arch_handle_exception (ctx, exc, FALSE);
 }
 
+#ifndef PLATFORM_WIN32
+static void
+add_signal_handler (int signo, gpointer handler)
+{
+       struct sigaction sa;
+
+#ifdef MONO_ARCH_USE_SIGACTION
+       sa.sa_sigaction = handler;
+       sigemptyset (&sa.sa_mask);
+       sa.sa_flags = SA_SIGINFO;
+#else
+       sa.sa_handler = handler;
+       sigemptyset (&sa.sa_mask);
+       sa.sa_flags = 0;
+#endif
+       g_assert (sigaction (signo, &sa, NULL) != -1);
+}
+#endif
+
 static void
 mono_runtime_install_handlers (void)
 {
-#ifndef PLATFORM_WIN32
+#ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
        struct sigaction sa;
 #endif
 
@@ -7940,58 +8135,27 @@ mono_runtime_install_handlers (void)
         * but it seems to work well with our current exception
         * handlers. If not we must call syscall directly instead 
         * of sigaction */
-       
+
        if (getenv ("MONO_DEBUG")) {
-               /* catch SIGINT */
-               sa.sa_handler = sigint_signal_handler;
-               sigemptyset (&sa.sa_mask);
-               sa.sa_flags = 0;
-               //g_assert (syscall (SYS_sigaction, SIGINT, &sa, NULL) != -1);
-               g_assert (sigaction (SIGINT, &sa, NULL) != -1);
+               add_signal_handler (SIGINT, sigint_signal_handler);
        }
 
-       /* catch SIGFPE */
-       sa.sa_handler = sigfpe_signal_handler;
-       sigemptyset (&sa.sa_mask);
-       sa.sa_flags = 0;
-       //g_assert (syscall (SYS_sigaction, SIGFPE, &sa, NULL) != -1);
-       g_assert (sigaction (SIGFPE, &sa, NULL) != -1);
+       add_signal_handler (SIGFPE, sigfpe_signal_handler);
+       add_signal_handler (SIGQUIT, sigquit_signal_handler);
+       add_signal_handler (SIGILL, sigill_signal_handler);
+       add_signal_handler (SIGBUS, sigsegv_signal_handler);
+       add_signal_handler (mono_thread_get_abort_signal (), sigusr1_signal_handler);
 
-       /* catch SIGQUIT */
-       sa.sa_handler = sigquit_signal_handler;
-       sigemptyset (&sa.sa_mask);
-       sa.sa_flags = 0;
-       g_assert (sigaction (SIGQUIT, &sa, NULL) != -1);
-
-       /* catch SIGILL */
-       sa.sa_handler = sigill_signal_handler;
-       sigemptyset (&sa.sa_mask);
-       sa.sa_flags = 0;
-       //g_assert (syscall (SYS_sigaction, SIGILL, &sa, NULL) != -1);
-       g_assert (sigaction (SIGILL, &sa, NULL) != -1);
-
-       /* catch thread abort signal */
-       sa.sa_handler = sigusr1_signal_handler;
-       sigemptyset (&sa.sa_mask);
-       sa.sa_flags = 0;
-       //g_assert (syscall (SYS_sigaction, SIGILL, &sa, NULL) != -1);
-
-       g_assert (sigaction (mono_thread_get_abort_signal (), &sa, NULL) != -1);
-
-#if 1
        /* catch SIGSEGV */
 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
        sa.sa_sigaction = sigsegv_signal_handler;
        sigemptyset (&sa.sa_mask);
-       sa.sa_flags = SA_SIGINFO | SA_STACK;
-#else
-       sa.sa_handler = sigsegv_signal_handler;
-       sigemptyset (&sa.sa_mask);
-       sa.sa_flags = 0;
-#endif
-       //g_assert (syscall (SYS_sigaction, SIGSEGV, &sa, NULL) != -1);
+       sa.sa_flags = SA_SIGINFO | SA_ONSTACK;
        g_assert (sigaction (SIGSEGV, &sa, NULL) != -1);
+#else
+       add_signal_handler (SIGSEGV, sigsegv_signal_handler);
 #endif
+
 #endif /* PLATFORM_WIN32 */
 }
 
@@ -8054,9 +8218,8 @@ mini_init (const char *filename)
        mono_install_handler (mono_arch_get_throw_exception ());
 #endif
        mono_install_stack_walk (mono_jit_walk_stack);
-       mono_install_get_config_dir ();
 
-       domain = mono_init (filename);
+       domain = mono_init_from_assembly (filename, filename);
        mono_init_icall ();
 
        mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info", 
@@ -8079,11 +8242,10 @@ mini_init (const char *filename)
        mono_register_jit_icall (mono_profiler_method_leave, "mono_profiler_method_leave", NULL, TRUE);
        mono_register_jit_icall (mono_trace_enter_method, "mono_trace_enter_method", NULL, TRUE);
        mono_register_jit_icall (mono_trace_leave_method, "mono_trace_leave_method", NULL, TRUE);
-
        mono_register_jit_icall (mono_get_lmf_addr, "mono_get_lmf_addr", helper_sig_ptr_void, TRUE);
        mono_register_jit_icall (mono_domain_get, "mono_domain_get", helper_sig_domain_get, TRUE);
 
-       /* fixme: we cant hanlde vararg methods this way, because the signature is not constant */
+       /* fixme: we cant handle vararg methods this way, because the signature is not constant */
        //mono_register_jit_icall (ves_array_element_address, "ves_array_element_address", NULL);
        //mono_register_jit_icall (mono_array_new_va, "mono_array_new_va", NULL);
 
@@ -8091,6 +8253,9 @@ mini_init (const char *filename)
        mono_register_jit_icall (mono_arch_get_throw_exception_by_name (), "mono_arch_throw_exception_by_name", 
                                 helper_sig_void_ptr, TRUE);
        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_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);
 
        /* 
         * NOTE, NOTE, NOTE, NOTE:
@@ -8105,18 +8270,23 @@ mini_init (const char *filename)
        mono_register_opcode_emulation (OP_LREM, "__emul_lrem", helper_sig_long_long_long, mono_llrem, FALSE);
        mono_register_opcode_emulation (OP_LREM_UN, "__emul_lrem_un", helper_sig_long_long_long, mono_llrem_un, FALSE);
 
+#ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
        mono_register_opcode_emulation (OP_LSHL, "__emul_lshl", helper_sig_long_long_int, mono_lshl, TRUE);
        mono_register_opcode_emulation (OP_LSHR, "__emul_lshr", helper_sig_long_long_int, mono_lshr, TRUE);
        mono_register_opcode_emulation (OP_LSHR_UN, "__emul_lshr_un", helper_sig_long_long_int, mono_lshr_un, TRUE);
+#endif
 
        mono_register_opcode_emulation (OP_FCONV_TO_U8, "__emul_fconv_to_u8", helper_sig_ulong_double, mono_fconv_u8, FALSE);
        mono_register_opcode_emulation (OP_FCONV_TO_U4, "__emul_fconv_to_u4", helper_sig_uint_double, mono_fconv_u4, FALSE);
-       mono_register_opcode_emulation (OP_FCONV_TO_OVF_I8, "__emul_fconv_to_ovf_i8", helper_sig_long_double, mono_fconv_ovf_i8, TRUE);
-       mono_register_opcode_emulation (OP_FCONV_TO_OVF_U8, "__emul_fconv_to_ovf_u8", helper_sig_ulong_double, mono_fconv_ovf_u8, TRUE);
+       mono_register_opcode_emulation (OP_FCONV_TO_OVF_I8, "__emul_fconv_to_ovf_i8", helper_sig_long_double, mono_fconv_ovf_i8, FALSE);
+       mono_register_opcode_emulation (OP_FCONV_TO_OVF_U8, "__emul_fconv_to_ovf_u8", helper_sig_ulong_double, mono_fconv_ovf_u8, FALSE);
 
 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
        mono_register_opcode_emulation (OP_FCONV_TO_I8, "__emul_fconv_to_i8", helper_sig_long_double, mono_fconv_i8, FALSE);
 #endif
+#ifdef MONO_ARCH_EMULATE_CONV_R8_UN
+       mono_register_opcode_emulation (CEE_CONV_R_UN, "__emul_conv_r_un", helper_sig_double_int, mono_conv_to_r8_un, FALSE);
+#endif
 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
        mono_register_opcode_emulation (OP_LCONV_TO_R8, "__emul_lconv_to_r8", helper_sig_double_long, mono_lconv_to_r8, FALSE);
 #endif
@@ -8133,7 +8303,9 @@ mini_init (const char *filename)
 #if SIZEOF_VOID_P == 4
        mono_register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", helper_sig_uint_double, mono_fconv_u4, TRUE);
 #else
+#ifdef __GNUC__
 #warning "fixme: add opcode emulation"
+#endif
 #endif
 
        /* other jit icalls */
@@ -8152,29 +8324,10 @@ mini_init (const char *filename)
        mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", helper_sig_object_new_specific, FALSE);
        mono_register_jit_icall (mono_array_new, "mono_array_new", helper_sig_newarr, FALSE);
        mono_register_jit_icall (mono_array_new_specific, "mono_array_new_specific", helper_sig_newarr_specific, FALSE);
-       mono_register_jit_icall (mono_string_to_utf16, "mono_string_to_utf16", helper_sig_ptr_obj, FALSE);
-       mono_register_jit_icall (mono_string_from_utf16, "mono_string_from_utf16", helper_sig_obj_ptr, FALSE);
-       mono_register_jit_icall (mono_string_new_wrapper, "mono_string_new_wrapper", helper_sig_obj_ptr, FALSE);
-       mono_register_jit_icall (mono_string_to_utf8, "mono_string_to_utf8", helper_sig_ptr_obj, FALSE);
-       mono_register_jit_icall (mono_string_to_bstr, "mono_string_to_bstr", helper_sig_ptr_obj, FALSE);
-       mono_register_jit_icall (mono_string_to_ansibstr, "mono_string_to_ansibstr", helper_sig_ptr_obj, FALSE);
-       mono_register_jit_icall (mono_string_builder_to_utf8, "mono_string_builder_to_utf8", helper_sig_ptr_obj, FALSE);
-       mono_register_jit_icall (mono_string_builder_to_utf16, "mono_string_builder_to_utf16", helper_sig_ptr_obj, FALSE);
-       mono_register_jit_icall (mono_array_to_savearray, "mono_array_to_savearray", helper_sig_ptr_obj, FALSE);
-       mono_register_jit_icall (mono_array_to_lparray, "mono_array_to_lparray", helper_sig_ptr_obj, FALSE);
-       mono_register_jit_icall (mono_delegate_to_ftnptr, "mono_delegate_to_ftnptr", helper_sig_ptr_obj, FALSE);
-       mono_register_jit_icall (mono_marshal_string_array, "mono_marshal_string_array", helper_sig_ptr_obj, FALSE);
-       mono_register_jit_icall (mono_string_utf8_to_builder, "mono_string_utf8_to_builder", helper_sig_void_ptr_ptr, FALSE);
-       mono_register_jit_icall (mono_string_utf16_to_builder, "mono_string_utf16_to_builder", helper_sig_void_ptr_ptr, FALSE);
-       mono_register_jit_icall (mono_marshal_free_array, "mono_marshal_free_array", helper_sig_void_ptr_ptr, FALSE);
-       mono_register_jit_icall (mono_string_to_byvalstr, "mono_string_to_byvalstr", helper_sig_void_ptr_ptr_ptr, FALSE);
-       mono_register_jit_icall (mono_string_to_byvalwstr, "mono_string_to_byvalwstr", helper_sig_void_ptr_ptr_ptr, FALSE);
-       mono_register_jit_icall (g_free, "g_free", helper_sig_void_ptr, FALSE);
        mono_register_jit_icall (mono_runtime_class_init, "mono_runtime_class_init", helper_sig_void_ptr, FALSE);
        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 (mono_object_castclass_mbyref, "mono_object_castclass", helper_sig_obj_obj_cls, FALSE);
 #endif
 
 #define JIT_RUNTIME_WORKS
@@ -8218,6 +8371,11 @@ print_jit_stats (void)
                g_print ("Used classes:           %ld\n", mono_stats.used_class_count);
                g_print ("Static data size:       %ld\n", mono_stats.class_static_data_size);
                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 ("Inflated types:         %ld\n", mono_stats.inflated_type_count);
+               g_print ("Generics metadata size: %ld\n", mono_stats.generics_metadata_size);
        }
 }
 
@@ -8230,7 +8388,7 @@ mini_cleanup (MonoDomain *domain)
         * fully working (mono_domain_finalize may invoke managed finalizers
         * and mono_runtime_cleanup will wait for other threads to finish).
         */
-       mono_domain_finalize (domain, -1);
+       mono_domain_finalize (domain, 2000);
 
        mono_runtime_cleanup (domain);
 
@@ -8257,19 +8415,17 @@ mono_set_defaults (int verbose_level, guint32 opts)
 static void
 mono_precompile_assembly (MonoAssembly *ass, void *user_data)
 {
-       MonoImage *image = ass->image;
-       MonoMethod *method;
+       MonoImage *image = mono_assembly_get_image (ass);
+       MonoMethod *method, *invoke;
        int i, count = 0;
 
        if (mini_verbose > 0)
-               printf ("PRECOMPILE: %s.\n", ass->image->name);
+               printf ("PRECOMPILE: %s.\n", mono_image_get_filename (image));
 
-       for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
+       for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
                method = mono_get_method (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL);
                if (method->flags & METHOD_ATTRIBUTE_ABSTRACT)
                        continue;
-               if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)
-                       continue;
 
                count++;
                if (mini_verbose > 1) {
@@ -8278,6 +8434,14 @@ mono_precompile_assembly (MonoAssembly *ass, void *user_data)
                        g_free (desc);
                }
                mono_compile_method (method);
+               if (strcmp (method->name, "Finalize") == 0) {
+                       invoke = mono_marshal_get_runtime_invoke (method);
+                       mono_compile_method (invoke);
+               }
+               if (method->klass->marshalbyref && method->signature->hasthis) {
+                       invoke = mono_marshal_get_remoting_invoke_with_check (method);
+                       mono_compile_method (invoke);
+               }
        }
 }