Mon Oct 15 10:37:15 CEST 2007 Paolo Molaro <lupus@ximian.com>
[mono.git] / mono / mini / mini.c
index 93c75d5309256d052321a5349c18d11709aa2fd7..40cbaa816f944c9d6a530720526358db085474dd 100644 (file)
@@ -36,7 +36,6 @@
 
 #include <mono/metadata/assembly.h>
 #include <mono/metadata/loader.h>
-#include <mono/metadata/cil-coff.h>
 #include <mono/metadata/tabledefs.h>
 #include <mono/metadata/class.h>
 #include <mono/metadata/object.h>
@@ -57,6 +56,7 @@
 #include <mono/metadata/environment.h>
 #include <mono/metadata/mono-debug.h>
 #include <mono/metadata/monitor.h>
+#include <mono/metadata/gc-internal.h>
 #include <mono/metadata/security-manager.h>
 #include <mono/metadata/threads-types.h>
 #include <mono/metadata/rawbuffer.h>
                g_free (field_fname);   \
                goto exception_exit;    \
        } while (0)
+#define GENERIC_SHARING_FAILURE do {   \
+               if (cfg->generic_sharing_context) {     \
+                       /* g_print ("sharing failed for method %s.%s in %s:%d\n", method->klass->name, method->name, __FILE__, __LINE__); */ \
+                       cfg->exception_type = MONO_EXCEPTION_GENERIC_SHARING_FAILED;    \
+                       goto exception_exit;    \
+               }                       \
+       } while (0)
 
 /* 
  * this is used to determine when some branch optimizations are possible: we exclude FP compares
@@ -135,7 +142,7 @@ static void dec_foreach (MonoInst *tree, MonoCompile *cfg);
 
 static int mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
                   int locals_offset, MonoInst *return_var, GList *dont_inline, MonoInst **inline_args, 
-                  guint inline_offset, gboolean is_virtual_call);
+                  guint inline_offset, gboolean is_virtual_call, MonoGenericContext *shared_context);
 
 /* helper methods signature */
 static MonoMethodSignature *helper_sig_class_init_trampoline = NULL;
@@ -150,6 +157,8 @@ gboolean mono_break_on_exc = FALSE;
 #ifndef DISABLE_AOT
 gboolean mono_compile_aot = FALSE;
 #endif
+MonoMethodDesc *mono_inject_async_exc_method = NULL;
+int mono_inject_async_exc_pos;
 
 static int mini_verbose = 0;
 
@@ -551,8 +560,8 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
                (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
                (dest)->ssa_op = MONO_SSA_LOAD; \
                (dest)->inst_i0 = arg_array [(num)];    \
-               (dest)->opcode = mono_type_to_ldind ((dest)->inst_i0->inst_vtype);      \
-               type_to_eval_stack_type (param_types [(num)], (dest));  \
+               (dest)->opcode = mini_type_to_ldind ((cfg), (dest)->inst_i0->inst_vtype); \
+               type_to_eval_stack_type ((cfg), param_types [(num)], (dest));   \
                (dest)->klass = (dest)->inst_i0->klass; \
        }} while (0)
 
@@ -560,8 +569,8 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
                (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
                (dest)->ssa_op = MONO_SSA_LOAD; \
                (dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)];       \
-               (dest)->opcode = mono_type_to_ldind ((dest)->inst_i0->inst_vtype);      \
-               type_to_eval_stack_type (header->locals [(num)], (dest));       \
+               (dest)->opcode = mini_type_to_ldind ((cfg), (dest)->inst_i0->inst_vtype); \
+               type_to_eval_stack_type ((cfg), header->locals [(num)], (dest));        \
                (dest)->klass = (dest)->inst_i0->klass; \
        } while (0)
 
@@ -604,8 +613,8 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
                (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
                (dest)->ssa_op = MONO_SSA_LOAD; \
                (dest)->inst_i0 = (cfg)->varinfo [(num)];       \
-               (dest)->opcode = mono_type_to_ldind ((dest)->inst_i0->inst_vtype);      \
-               type_to_eval_stack_type ((dest)->inst_i0->inst_vtype, (dest));  \
+               (dest)->opcode = mini_type_to_ldind ((cfg), (dest)->inst_i0->inst_vtype); \
+               type_to_eval_stack_type ((cfg), (dest)->inst_i0->inst_vtype, (dest));   \
                (dest)->klass = (dest)->inst_i0->klass; \
        } while (0)
 
@@ -625,15 +634,15 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
 #define NEW_INDLOAD(cfg,dest,addr,vtype) do {  \
                (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
                (dest)->inst_left = addr;       \
-               (dest)->opcode = mono_type_to_ldind (vtype);    \
-               type_to_eval_stack_type (vtype, (dest));        \
+               (dest)->opcode = mini_type_to_ldind ((cfg), vtype);     \
+               type_to_eval_stack_type ((cfg), vtype, (dest)); \
                /* FIXME: (dest)->klass = (dest)->inst_i0->klass;*/     \
        } while (0)
 
 #define NEW_INDSTORE(cfg,dest,addr,value,vtype) do {   \
                (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
                (dest)->inst_i0 = addr; \
-               (dest)->opcode = mono_type_to_stind (vtype);    \
+               (dest)->opcode = mini_type_to_stind ((cfg), vtype);     \
                (dest)->inst_i1 = (value);      \
                /* FIXME: (dest)->klass = (dest)->inst_i0->klass;*/     \
        } while (0)
@@ -642,14 +651,14 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
                (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
                (dest)->ssa_op = MONO_SSA_STORE;        \
                (dest)->inst_i0 = (cfg)->varinfo [(num)];       \
-               (dest)->opcode = mono_type_to_stind ((dest)->inst_i0->inst_vtype);      \
+               (dest)->opcode = mini_type_to_stind ((cfg), (dest)->inst_i0->inst_vtype); \
                (dest)->inst_i1 = (inst);       \
                (dest)->klass = (dest)->inst_i0->klass; \
        } while (0)
 
 #define NEW_LOCSTORE(cfg,dest,num,inst) do {   \
                (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
-               (dest)->opcode = mono_type_to_stind (header->locals [(num)]);   \
+               (dest)->opcode = mini_type_to_stind ((cfg), header->locals [(num)]); \
                (dest)->ssa_op = MONO_SSA_STORE;        \
                (dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)];       \
                (dest)->inst_i1 = (inst);       \
@@ -659,13 +668,33 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
 #define NEW_ARGSTORE(cfg,dest,num,inst) do {   \
                 if (arg_array [(num)]->opcode == OP_ICONST) goto inline_failure; \
                (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
-               (dest)->opcode = mono_type_to_stind (param_types [(num)]);      \
+               (dest)->opcode = mini_type_to_stind ((cfg), param_types [(num)]); \
                (dest)->ssa_op = MONO_SSA_STORE;        \
                (dest)->inst_i0 = arg_array [(num)];    \
                (dest)->inst_i1 = (inst);       \
                (dest)->klass = (dest)->inst_i0->klass; \
        } while (0)
 
+#define NEW_MEMCPY(cfg,dest,dst,src,memcpy_size,memcpy_align) do { \
+               MONO_INST_NEW (cfg, dest, OP_MEMCPY); \
+        (dest)->inst_left = (dst); \
+               (dest)->inst_right = (src); \
+               (dest)->cil_code = ip; \
+        (dest)->backend.memcpy_args = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoMemcpyArgs)); \
+               (dest)->backend.memcpy_args->size = (memcpy_size); \
+               (dest)->backend.memcpy_args->align = (memcpy_align); \
+    } while (0)
+
+#define NEW_MEMSET(cfg,dest,dst,imm,memcpy_size,memcpy_align) do { \
+               MONO_INST_NEW (cfg, dest, OP_MEMSET); \
+        (dest)->inst_left = (dst); \
+               (dest)->inst_imm = (imm); \
+               (dest)->cil_code = ip; \
+        (dest)->backend.memcpy_args = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoMemcpyArgs)); \
+               (dest)->backend.memcpy_args->size = (memcpy_size); \
+               (dest)->backend.memcpy_args->align = (memcpy_align); \
+    } while (0)
+
 #define NEW_DUMMY_USE(cfg,dest,load) do { \
                (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
                (dest)->opcode = OP_DUMMY_USE; \
@@ -1164,7 +1193,7 @@ condbr_to_fp_br (int opcode)
  * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
  */
 static void
-type_to_eval_stack_type (MonoType *type, MonoInst *inst)
+type_to_eval_stack_type (MonoCompile *cfg, MonoType *type, MonoInst *inst)
 {
        MonoClass *klass;
 
@@ -1226,6 +1255,15 @@ handle_enum:
        case MONO_TYPE_GENERICINST:
                type = &type->data.generic_class->container_class->byval_arg;
                goto handle_enum;
+       case MONO_TYPE_VAR :
+       case MONO_TYPE_MVAR :
+               /* FIXME: all the arguments must be references for now,
+                * later look inside cfg and see if the arg num is
+                * really a reference
+                */
+               g_assert (cfg->generic_sharing_context);
+               inst->type = STACK_OBJ;
+               return;
        default:
                g_error ("unknown type 0x%02x in eval stack type", type->type);
        }
@@ -1602,6 +1640,34 @@ check_values_to_signature (MonoInst *args, MonoType *this, MonoMethodSignature *
 }
 #endif
 
+static guint
+mini_type_to_ldind (MonoCompile* cfg, MonoType *type)
+{
+       if (cfg->generic_sharing_context && !type->byref) {
+               /* FIXME: all the arguments must be references for now,
+                * later look inside cfg and see if the arg num is
+                * really a reference
+                */
+               if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)
+                       return CEE_LDIND_REF;
+       }
+       return mono_type_to_ldind (type);
+}
+
+static guint
+mini_type_to_stind (MonoCompile* cfg, MonoType *type)
+{
+       if (cfg->generic_sharing_context && !type->byref) {
+               /* FIXME: all the arguments must be references for now,
+                * later look inside cfg and see if the arg num is
+                * really a reference
+                */
+               if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)
+                       return CEE_STIND_REF;
+       }
+       return mono_type_to_stind (type);
+}
+
 /*
  * When we need a pointer to the current domain many times in a method, we
  * call mono_domain_get() once and we store the result in a local variable.
@@ -1675,8 +1741,8 @@ mono_compile_make_var_load (MonoCompile *cfg, MonoInst *dest, gssize var_index)
        memset (dest, 0, sizeof (MonoInst));
        dest->ssa_op = MONO_SSA_LOAD;
        dest->inst_i0 = cfg->varinfo [var_index];
-       dest->opcode = mono_type_to_ldind (dest->inst_i0->inst_vtype);
-       type_to_eval_stack_type (dest->inst_i0->inst_vtype, dest);
+       dest->opcode = mini_type_to_ldind (cfg, dest->inst_i0->inst_vtype);
+       type_to_eval_stack_type (cfg, dest->inst_i0->inst_vtype, dest);
        dest->klass = dest->inst_i0->klass;
 }
 
@@ -1833,6 +1899,7 @@ mono_add_varcopy_to_end (MonoCompile *cfg, MonoBasicBlock *bb, int src, int dest
        NEW_TEMPLOAD (cfg, load, src);
 
        NEW_TEMPSTORE (cfg, inst, dest, load);
+       /* FIXME: handle CEE_STIND_R4 */
        if (inst->opcode == CEE_STOBJ) {
                NEW_TEMPLOADA (cfg, inst, dest);
                handle_stobj (cfg, bb, inst, load, NULL, inst->klass, TRUE, FALSE, FALSE);
@@ -2033,6 +2100,7 @@ handle_stack_args (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **sp, int coun
        for (i = 0; i < count; ++i) {
                /* add store ops at the end of the bb, before the branch */
                NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
+               /* FIXME: handle CEE_STIND_R4 */
                if (inst->opcode == CEE_STOBJ) {
                        NEW_TEMPLOADA (cfg, inst, locals [i]->inst_c0);
                        handle_stobj (cfg, bb, inst, sp [i], sp [i]->cil_code, inst->klass, TRUE, FALSE, FALSE);
@@ -2185,6 +2253,7 @@ handle_loaded_temps (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst **stack,
                        temp->flags |= MONO_INST_IS_TEMP;
                        NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
                        store->cil_code = ins->cil_code;
+                       /* FIXME: handle CEE_STIND_R4 */
                        if (store->opcode == CEE_STOBJ) {
                                NEW_TEMPLOADA (cfg, store, temp->inst_c0);
                                handle_stobj (cfg, bblock, store, ins, ins->cil_code, temp->klass, FALSE, FALSE, FALSE);
@@ -2309,6 +2378,16 @@ target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
                        /* FIXME: check type compatibility */
                        return 0;
                }
+       case MONO_TYPE_VAR:
+       case MONO_TYPE_MVAR:
+               /* FIXME: all the arguments must be references for now,
+                * later look inside cfg and see if the arg num is
+                * really a reference
+                */
+               g_assert (cfg->generic_sharing_context);
+               if (arg->type != STACK_OBJ)
+                       return 1;
+               return 0;
        default:
                g_error ("unknown type 0x%02x in target_type_is_incompatible", simple_type->type);
        }
@@ -2420,7 +2499,7 @@ mono_spill_call (MonoCompile *cfg, MonoBasicBlock *bblock, MonoCallInst *call, M
                        call->inst.opcode = CEE_CALL;
                        temp = mono_compile_create_var (cfg, &mono_defaults.string_class->byval_arg, OP_LOCAL);
                } else {
-                       type_to_eval_stack_type (ret, ins);
+                       type_to_eval_stack_type (cfg, ret, ins);
                        temp = mono_compile_create_var (cfg, ret, OP_LOCAL);
                }
                
@@ -2454,6 +2533,7 @@ mono_spill_call (MonoCompile *cfg, MonoBasicBlock *bblock, MonoCallInst *call, M
                                MONO_ADD_INS (bblock, ins);
                } else {
                        NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
+                       /* FIXME: handle CEE_STIND_R4 */
                        store->cil_code = ip;
                        if (to_end)
                                mono_add_ins_to_end (bblock, store);
@@ -2501,7 +2581,7 @@ mono_emit_call_args (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignatu
        call->args = args;
        call->signature = sig;
        call = mono_arch_call_opcode (cfg, bblock, call, virtual);
-       type_to_eval_stack_type (sig->ret, &call->inst);
+       type_to_eval_stack_type (cfg, sig->ret, &call->inst);
 
        for (arg = call->out_args; arg;) {
                MonoInst *narg = arg->next;
@@ -2630,6 +2710,7 @@ mono_emulate_opcode (MonoCompile *cfg, MonoInst *tree, MonoInst **iargs, MonoJit
                temp = mono_compile_create_var (cfg, info->sig->ret, OP_LOCAL);
                temp->flags |= MONO_INST_IS_TEMP;
                NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
+               /* FIXME: handle CEE_STIND_R4 */
                store->cil_code = tree->cil_code;
        } else {
                store = ins;
@@ -2668,6 +2749,32 @@ mono_emulate_opcode (MonoCompile *cfg, MonoInst *tree, MonoInst **iargs, MonoJit
        }
 }
 
+/*
+ * This entry point could be used later for arbitrary method
+ * redirection.
+ */
+inline static int
+mini_redirect_call (int *temp, MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method,  
+                      MonoMethodSignature *signature, MonoInst **args, const guint8 *ip, MonoInst *this)
+{
+
+       if (method->klass == mono_defaults.string_class) {
+               /* managed string allocation support */
+               if (strcmp (method->name, "InternalAllocateStr") == 0) {
+                       MonoInst *iargs [2];
+                       MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
+                       MonoMethod *managed_alloc = mono_gc_get_managed_allocator (vtable, FALSE);
+                       if (!managed_alloc)
+                               return FALSE;
+                       NEW_VTABLECONST (cfg, iargs [0], vtable);
+                       iargs [1] = args [0];
+                       *temp = mono_emit_method_call_spilled (cfg, bblock, managed_alloc, mono_method_signature (managed_alloc), iargs, ip, this);
+                       return TRUE;
+               }
+       }
+       return FALSE;
+}
+
 static MonoMethodSignature *
 mono_get_array_new_va_signature (int arity)
 {
@@ -2817,11 +2924,7 @@ handle_stobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, MonoInst
                        NEW_DUMMY_STORE (cfg, inst, dest->inst_i0->inst_c0);
                        MONO_ADD_INS (bblock, inst);
                }
-               MONO_INST_NEW (cfg, inst, OP_MEMCPY);
-               inst->inst_left = dest;
-               inst->inst_right = src;
-               inst->cil_code = ip;
-               inst->backend.size = n;
+               NEW_MEMCPY (cfg, inst, dest, src, n, align);
                MONO_ADD_INS (bblock, inst);
                return;
        }
@@ -2851,44 +2954,36 @@ handle_initobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, const
        MonoInst *iargs [3];
        MonoInst *ins, *zero_int32;
        int n;
+       guint32 align;
        MonoMethod *memset_method;
 
        NEW_ICONST (cfg, zero_int32, 0);
 
        mono_class_init (klass);
-       n = mono_class_value_size (klass, NULL);
+       n = mono_class_value_size (klass, &align);
        MONO_INST_NEW (cfg, ins, 0);
        ins->cil_code = ip;
        ins->inst_left = dest;
        ins->inst_right = zero_int32;
-       switch (n) {
-       case 1:
+       if (n == 1) {
                ins->opcode = CEE_STIND_I1;
                MONO_ADD_INS (bblock, ins);
-               break;
-       case 2:
+       } else if ((n == 2) && (align >= 2)) {
                ins->opcode = CEE_STIND_I2;
                MONO_ADD_INS (bblock, ins);
-               break;
-       case 4:
+       } else if ((n == 2) && (align >= 4)) {
                ins->opcode = CEE_STIND_I4;
                MONO_ADD_INS (bblock, ins);
-               break;
-       default:
-               if (n <= sizeof (gpointer) * 5) {
-                       ins->opcode = OP_MEMSET;
-                       ins->inst_imm = 0;
-                       ins->backend.size = n;
-                       MONO_ADD_INS (bblock, ins);
-                       break;
-               }
+       } else if (n <= sizeof (gpointer) * 5) {
+               NEW_MEMSET (cfg, ins, dest, 0, n, align);
+               MONO_ADD_INS (bblock, ins);
+       } else {
                memset_method = get_memset_method ();
                handle_loaded_temps (cfg, bblock, stack_start, sp);
                iargs [0] = dest;
                NEW_ICONST (cfg, iargs [1], 0);
                NEW_ICONST (cfg, iargs [2], n);
                mono_emit_method_call_spilled (cfg, bblock, memset_method, memset_method->signature, iargs, ip, NULL);
-               break;
        }
 }
 
@@ -2910,8 +3005,13 @@ handle_alloc (MonoCompile *cfg, MonoBasicBlock *bblock, MonoClass *klass, gboole
                return mono_emit_jit_icall (cfg, bblock, mono_helper_newobj_mscorlib, iargs, ip);
        } else {
                MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
+               MonoMethod *managed_alloc = mono_gc_get_managed_allocator (vtable, for_box);
                gboolean pass_lw;
 
+               if (managed_alloc) {
+                       NEW_VTABLECONST (cfg, iargs [0], vtable);
+                       return mono_emit_method_call_spilled (cfg, bblock, managed_alloc, mono_method_signature (managed_alloc), iargs, ip, NULL);
+               }
                alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
                if (pass_lw) {
                        guint32 lw = vtable->klass->instance_size;
@@ -2963,7 +3063,7 @@ handle_box (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *val, const gucha
        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->opcode = mini_type_to_stind (cfg, &klass->byval_arg);
        vstore->cil_code = ip;
        vstore->inst_left = add;
        vstore->inst_right = val;
@@ -3314,7 +3414,7 @@ mini_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSigna
                MonoInst *ldelem, *store, *load;
                MonoClass *eklass = mono_class_from_mono_type (fsig->params [1]);
                int n;
-               n = mono_type_to_stind (&eklass->byval_arg);
+               n = mini_type_to_stind (cfg, &eklass->byval_arg);
                if (n == CEE_STOBJ)
                        return NULL;
                sp [0] = args [0];
@@ -3322,9 +3422,8 @@ mini_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSigna
                NEW_LDELEMA (cfg, ldelem, sp, eklass);
                ldelem->flags |= MONO_INST_NORANGECHECK;
                MONO_INST_NEW (cfg, store, n);
-               n = mono_type_to_ldind (&eklass->byval_arg);
-               MONO_INST_NEW (cfg, load, mono_type_to_ldind (&eklass->byval_arg));
-               type_to_eval_stack_type (&eklass->byval_arg, load);
+               MONO_INST_NEW (cfg, load, mini_type_to_ldind (cfg, &eklass->byval_arg));
+               type_to_eval_stack_type (cfg, &eklass->byval_arg, load);
                load->inst_left = ldelem;
                store->inst_left = args [2];
                store->inst_right = load;
@@ -3383,6 +3482,7 @@ mono_save_args (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *s
                        temp = mono_compile_create_var (cfg, type_from_stack_type (*sp), OP_LOCAL);
                        *args++ = temp;
                        NEW_TEMPSTORE (cfg, store, temp->inst_c0, *sp);
+                       /* FIXME: handle CEE_STIND_R4 */
                        store->cil_code = sp [0]->cil_code;
                        MONO_ADD_INS (bblock, store);
                }
@@ -3397,6 +3497,7 @@ mono_save_args (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *s
                        *args++ = temp;
                        NEW_TEMPSTORE (cfg, store, temp->inst_c0, *sp);
                        store->cil_code = sp [0]->cil_code;
+                       /* FIXME: handle CEE_STIND_R4 */
                        if (store->opcode == CEE_STOBJ) {
                                NEW_TEMPLOADA (cfg, store, temp->inst_c0);
                                handle_stobj (cfg, bblock, store, *sp, sp [0]->cil_code, temp->klass, FALSE, FALSE, FALSE);
@@ -3460,7 +3561,7 @@ static gboolean check_inline_caller_method_name_limit (MonoMethod *caller_method
 
 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, gboolean inline_allways)
+               guchar *ip, guint real_offset, GList *dont_inline, MonoBasicBlock **last_b, gboolean inline_allways, MonoGenericContext *shared_context)
 {
        MonoInst *ins, *rvar = NULL;
        MonoMethodHeader *cheader;
@@ -3502,7 +3603,7 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig,
        new_locals_offset = cfg->num_varinfo;
        for (i = 0; i < cheader->num_locals; ++i)
                mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
-       
+
        /* allocate starte and end blocks */
        sbblock = NEW_BBLOCK (cfg);
        sbblock->block_num = cfg->num_bblocks++;
@@ -3518,7 +3619,7 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig,
        prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
        prev_cil_start = cfg->cil_start;
 
-       costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, new_locals_offset, rvar, dont_inline, sp, real_offset, *ip == CEE_CALLVIRT);
+       costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, new_locals_offset, rvar, dont_inline, sp, real_offset, *ip == CEE_CALLVIRT, shared_context);
 
        cfg->inlined_method = prev_inlined_method;
        cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
@@ -3702,6 +3803,7 @@ emit_tree (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ins, const guint8
        temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
        temp->flags |= MONO_INST_IS_TEMP;
        NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
+       /* FIXME: handle CEE_STIND_R4 */
        store->cil_code = ins->cil_code;
        MONO_ADD_INS (bblock, store);
        NEW_TEMPLOAD (cfg, load, temp->inst_c0);
@@ -3755,15 +3857,11 @@ gboolean check_linkdemand (MonoCompile *cfg, MonoMethod *caller, MonoMethod *cal
 
        if (result == MONO_JIT_LINKDEMAND_ECMA) {
                /* Generate code to throw a SecurityException before the actual call/link */
-               MonoAssembly *assembly = mono_image_get_assembly (caller->klass->image);
-               MonoReflectionAssembly *refass = (MonoReflectionAssembly*) mono_assembly_get_object (cfg->domain, assembly);
-               MonoReflectionMethod *refmet = mono_method_get_object (cfg->domain, caller, NULL);
                MonoSecurityManager *secman = mono_security_manager_get_methods ();
-               MonoInst *args [3];
+               MonoInst *args [2];
 
                NEW_ICONST (cfg, args [0], 4);
-               NEW_PCONST (cfg, args [1], refass);
-               NEW_PCONST (cfg, args [2], refmet);
+               NEW_METHODCONST (cfg, args [1], caller);
                mono_emit_method_call_spilled (cfg, bblock, secman->linkdemandsecurityexception, mono_method_signature (secman->linkdemandsecurityexception), args, ip, NULL);
        } else if (cfg->exception_type == MONO_EXCEPTION_NONE) {
                 /* don't hide previous results */
@@ -3940,7 +4038,7 @@ set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsign
 static int
 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
                   int locals_offset, MonoInst *return_var, GList *dont_inline, MonoInst **inline_args, 
-                  guint inline_offset, gboolean is_virtual_call)
+                  guint inline_offset, gboolean is_virtual_call, MonoGenericContext *shared_context)
 {
        MonoInst *zero_int32, *zero_int64, *zero_ptr, *zero_obj, *zero_r8;
        MonoInst *ins, **sp, **stack_start;
@@ -3999,7 +4097,10 @@ 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 (sig->is_inflated)
+       if (cfg->generic_sharing_context) {
+               g_assert (shared_context);
+               generic_context = shared_context;
+       } else if (sig->is_inflated)
                generic_context = mono_method_get_context (method);
        else if (generic_container)
                generic_context = &generic_container->context;
@@ -4157,12 +4258,16 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
                                pinvoke = FALSE;
                        }
+                       if (custom)
+                               mono_custom_attrs_free (custom);
 
                        if (pinvoke) {
                                custom = mono_custom_attrs_from_class (wrapped->klass);
                                if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
                                        pinvoke = FALSE;
                                }
+                               if (custom)
+                                       mono_custom_attrs_free (custom);
                        }
                } else {
                        /* not a P/Invoke after all */
@@ -4597,6 +4702,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                temp->cil_code = ip;
                                NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
                                store->cil_code = ip;
+                               /* FIXME: handle CEE_STIND_R4 */
                                if (store->opcode == CEE_STOBJ) {
                                        NEW_TEMPLOADA (cfg, store, temp->inst_c0);
                                        handle_stobj (cfg, bblock, store, sp [0], sp [0]->cil_code, store->klass, TRUE, FALSE, FALSE);
@@ -4634,6 +4740,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (!cmethod)
                                goto load_error;
 
+                       if (cfg->generic_sharing_context && mono_method_check_context_used (cmethod, generic_context))
+                               GENERIC_SHARING_FAILURE;
+
                        if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
                                if (check_linkdemand (cfg, method, cmethod, bblock, ip))
                                        INLINE_FAILURE;
@@ -4730,6 +4839,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (cmethod && cmethod->klass->generic_container)
                                UNVERIFIED;
 
+                       if (cfg->generic_sharing_context && cmethod && mono_method_check_context_used (cmethod, generic_context))
+                               GENERIC_SHARING_FAILURE;
+
                        CHECK_STACK (n);
 
                        //g_assert (!virtual || fsig->hasthis);
@@ -4749,8 +4861,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                         * 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);
+                                       MONO_INST_NEW (cfg, load, mini_type_to_ldind (cfg, &constrained_call->byval_arg));
+                                       type_to_eval_stack_type (cfg, &constrained_call->byval_arg, load);
                                        load->cil_code = ip;
                                        load->inst_left = sp [0];
                                        sp [0] = handle_box (cfg, bblock, load, ip, constrained_call);
@@ -4849,6 +4961,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                                        NEW_ARGSTORE (cfg, ins, i, sp [i]);
                                        ins->cil_code = ip;
+                                       /* FIXME: handle CEE_STIND_R4 */
                                        if (ins->opcode == CEE_STOBJ) {
                                                NEW_ARGLOADA (cfg, ins, i);
                                                handle_stobj (cfg, bblock, ins, sp [i], sp [i]->cil_code, ins->klass, FALSE, FALSE, FALSE);
@@ -4874,7 +4987,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                if (MONO_TYPE_IS_VOID (fsig->ret)) {
                                        MONO_ADD_INS (bblock, ins);
                                } else {
-                                       type_to_eval_stack_type (fsig->ret, ins);
+                                       type_to_eval_stack_type (cfg, fsig->ret, ins);
                                        *sp = ins;
                                        sp++;
                                }
@@ -4902,7 +5015,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        allways = TRUE;
                                }
 
-                               if ((costs = inline_method (cfg, cmethod, fsig, bblock, sp, ip, real_offset, dont_inline, &ebblock, allways))) {
+                               if ((costs = inline_method (cfg, cmethod, fsig, bblock, sp, ip, real_offset, dont_inline, &ebblock, allways, shared_context))) {
                                        ip += 5;
                                        real_offset += 5;
 
@@ -4940,6 +5053,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                                if (!has_vtargs) {
                                        for (i = 0; i < n; ++i) {
+                                               /* FIXME: handle CEE_STIND_R4 */
                                                NEW_ARGSTORE (cfg, ins, i, sp [i]);
                                                ins->cil_code = ip;
                                                MONO_ADD_INS (bblock, ins);
@@ -4987,6 +5101,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                                                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]);
+                                               /* FIXME: handle CEE_STIND_R4 */
                                                store->cil_code = ip;
                                                MONO_ADD_INS (bblock, store);
                                                NEW_TEMPLOAD (cfg, iargs [1], to_store->inst_c0);
@@ -5006,6 +5121,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        addr = mini_get_ldelema_ins (cfg, bblock, cmethod, sp, ip, TRUE);
                                        NEW_INDSTORE (cfg, ins, addr, sp [fsig->param_count], fsig->params [fsig->param_count - 1]);
                                        ins->cil_code = ip;
+                                       /* FIXME: handle CEE_STIND_R4 */
                                        if (ins->opcode == CEE_STOBJ) {
                                                handle_stobj (cfg, bblock, addr, sp [fsig->param_count], ip, mono_class_from_mono_type (fsig->params [fsig->param_count-1]), FALSE, FALSE, TRUE);
                                        } else {
@@ -5028,7 +5144,12 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        } else {
                                /* Prevent inlining of methods which call other methods */
                                INLINE_FAILURE;
-                               if (ip_in_bb (cfg, bblock, ip + 5) 
+                               if (mini_redirect_call (&temp, cfg, bblock, cmethod, fsig, sp, ip, virtual ? sp [0] : NULL)) {
+                                       if (temp != -1) {
+                                               NEW_TEMPLOAD (cfg, *sp, temp);
+                                               sp++;
+                                       }
+                               } else if (ip_in_bb (cfg, bblock, ip + 5) 
                                    && (!MONO_TYPE_ISSTRUCT (fsig->ret))
                                    && (!MONO_TYPE_IS_VOID (fsig->ret) || cmethod->string_ctor)
                                    && (CODE_IS_STLOC (ip + 5) || ip [5] == CEE_POP || ip [5] == CEE_RET)) {
@@ -5057,6 +5178,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        //g_assert (returnvar != -1);
                                        NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
                                        store->cil_code = sp [0]->cil_code;
+                                       /* FIXME: handle CEE_STIND_R4 */
                                        if (store->opcode == CEE_STOBJ) {
                                                g_assert_not_reached ();
                                                NEW_TEMPLOADA (cfg, store, return_var->inst_c0);
@@ -5071,7 +5193,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        CHECK_STACK (1);
                                        --sp;
                                        MONO_INST_NEW (cfg, ins, OP_NOP);
-                                       ins->opcode = mono_type_to_stind (mono_method_signature (method)->ret);
+                                       ins->opcode = mini_type_to_stind (cfg, mono_method_signature (method)->ret);
                                        if (ins->opcode == CEE_STOBJ) {
                                                NEW_RETLOADA (cfg, ins);
                                                /* FIXME: it is possible some optimization will pass the a heap pointer for the struct address, so we'll need the write barrier */
@@ -5498,14 +5620,12 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                store->inst_i1 = load;
                                store->flags |= ins_flag;
                        } else {
-                               n = mono_class_value_size (klass, NULL);
+                               guint32 align;
+
+                               n = mono_class_value_size (klass, &align);
                                if ((cfg->opt & MONO_OPT_INTRINS) && n <= 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->backend.size = n;
+                                       NEW_MEMCPY (cfg, copy, sp [0], sp [1], n, align);
                                        MONO_ADD_INS (bblock, copy);
                                } else {
                                        MonoMethod *memcpy_method = get_memcpy_method ();
@@ -5525,6 +5645,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        MonoInst *iargs [3];
                        int loc_index = -1;
                        int stloc_len = 0;
+                       guint32 align;
+
                        CHECK_OPSIZE (5);
                        CHECK_STACK (1);
                        --sp;
@@ -5565,6 +5687,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                CHECK_LOCAL (loc_index);
                                NEW_LOCSTORE (cfg, ins, loc_index, *sp);
 
+                               /* FIXME: handle CEE_STIND_R4 */
                                if (ins->opcode == CEE_STOBJ) {
                                        handle_loaded_temps (cfg, bblock, stack_start, sp);
                                        ins->cil_code = ip;
@@ -5577,16 +5700,12 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                }
                        }
 
-                       n = mono_class_value_size (klass, NULL);
+                       n = mono_class_value_size (klass, &align);
                        ins = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
                        NEW_TEMPLOADA (cfg, iargs [0], ins->inst_c0);
                        if ((cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
                                MonoInst *copy;
-                               MONO_INST_NEW (cfg, copy, OP_MEMCPY);
-                               copy->inst_left = iargs [0];
-                               copy->inst_right = *sp;
-                               copy->cil_code = ip;
-                               copy->backend.size = n;
+                               NEW_MEMCPY (cfg, copy, iargs [0], *sp, n, align);
                                MONO_ADD_INS (bblock, copy);
                        } else {
                                MonoMethod *memcpy_method = get_memcpy_method ();
@@ -5686,7 +5805,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        MonoInst *iargs [2];
                        MonoMethodSignature *fsig;
                        int temp;
-                       
+
                        CHECK_OPSIZE (5);
                        token = read32 (ip + 1);
                        cmethod = mini_get_method (method, token, NULL, generic_context);
@@ -5699,6 +5818,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (!mono_class_init (cmethod->klass))
                                goto load_error;
 
+                       if (cfg->generic_sharing_context && mono_method_check_context_used (cmethod, generic_context))
+                               GENERIC_SHARING_FAILURE;
+
                        if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
                                if (check_linkdemand (cfg, method, cmethod, bblock, ip))
                                        INLINE_FAILURE;
@@ -5759,7 +5881,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, FALSE))) {
+                                       if ((costs = inline_method (cfg, cmethod, fsig, bblock, sp, ip, real_offset, dont_inline, &ebblock, FALSE, shared_context))) {
 
                                                ip += 5;
                                                real_offset += 5;
@@ -5808,6 +5930,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (sp [0]->type != STACK_OBJ)
                                UNVERIFIED;
 
+                       if (cfg->generic_sharing_context && mono_class_check_context_used (klass, generic_context))
+                               GENERIC_SHARING_FAILURE;
+
                        /* Needed by the code generated in inssel.brg */
                        mono_get_got_var (cfg);
 
@@ -5823,7 +5948,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                iargs [0] = sp [0];
                                
                                costs = inline_method (cfg, mono_isinst, mono_method_signature (mono_isinst), bblock, 
-                                                          iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
+                                                      iargs, ip, real_offset, dont_inline, &ebblock, TRUE, shared_context);
                        
                                g_assert (costs > 0);
                                
@@ -5854,6 +5979,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                case CEE_UNBOX_ANY: {
                        MonoInst *add, *vtoffset;
                        MonoInst *iargs [3];
+                       guint32 align;
 
                        CHECK_STACK (1);
                        --sp;
@@ -5862,6 +5988,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        klass = mini_get_class (method, token, generic_context);
                        CHECK_TYPELOAD (klass);
 
+                       if (cfg->generic_sharing_context && mono_class_check_context_used (klass, generic_context))
+                               GENERIC_SHARING_FAILURE;
+
                        if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
                                /* CASTCLASS */
                                if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
@@ -5875,7 +6004,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        iargs [0] = sp [0];
                                        
                                        costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), bblock, 
-                                                                  iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
+                                                       iargs, ip, real_offset, dont_inline, &ebblock, TRUE, shared_context);
                                
                                        g_assert (costs > 0);
                                        
@@ -5929,16 +6058,12 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        *sp = add;
                        ip += 5;
                        /* LDOBJ impl */
-                       n = mono_class_value_size (klass, NULL);
+                       n = mono_class_value_size (klass, &align);
                        ins = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
                        NEW_TEMPLOADA (cfg, iargs [0], ins->inst_c0);
                        if ((cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
                                MonoInst *copy;
-                               MONO_INST_NEW (cfg, copy, OP_MEMCPY);
-                               copy->inst_left = iargs [0];
-                               copy->inst_right = *sp;
-                               copy->cil_code = ip;
-                               copy->backend.size = n;
+                               NEW_MEMCPY (cfg, copy, iargs [0], *sp, n, align);
                                MONO_ADD_INS (bblock, copy);
                        } else {
                                MonoMethod *memcpy_method = get_memcpy_method ();
@@ -5963,6 +6088,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        klass = mini_get_class (method, token, generic_context);
                        CHECK_TYPELOAD (klass);
 
+                       if (cfg->generic_sharing_context && mono_class_check_context_used (klass, generic_context))
+                               GENERIC_SHARING_FAILURE;
+
                        if (mono_class_is_nullable (klass)) {
                                int v = handle_unbox_nullable (cfg, bblock, *sp, ip, klass);
                                NEW_TEMPLOAD (cfg, *sp, v);
@@ -6002,6 +6130,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (sp [0]->type != STACK_OBJ)
                                UNVERIFIED;
 
+                       if (cfg->generic_sharing_context && mono_class_check_context_used (klass, generic_context))
+                               GENERIC_SHARING_FAILURE;
+
                        /* Needed by the code generated in inssel.brg */
                        mono_get_got_var (cfg);
                
@@ -6017,7 +6148,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                iargs [0] = sp [0];
                                
                                costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), bblock, 
-                                                          iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
+                                               iargs, ip, real_offset, dont_inline, &ebblock, TRUE, shared_context);
                        
                                g_assert (costs > 0);
                                
@@ -6113,7 +6244,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                                        if (cfg->opt & MONO_OPT_INLINE) {
                                                costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), bblock, 
-                                                                      iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
+                                                               iargs, ip, real_offset, dont_inline, &ebblock, TRUE, shared_context);
                                                g_assert (costs > 0);
                                                      
                                                ip += 5;
@@ -6133,7 +6264,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                mono_emit_method_call_spilled (cfg, bblock, stfld_wrapper, mono_method_signature (stfld_wrapper), iargs, ip, NULL);
                                        }
 #if HAVE_WRITE_BARRIERS
-                               } else if (mono_type_to_stind (field->type) == CEE_STIND_REF) {
+                               } else if (mini_type_to_stind (cfg, field->type) == CEE_STIND_REF) {
                                        /* insert call to write barrier */
                                        MonoMethod *write_barrier = mono_marshal_get_write_barrier ();
                                        MonoInst *iargs [2];
@@ -6149,7 +6280,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        mono_emit_method_call_spilled (cfg, bblock, write_barrier, mono_method_signature (write_barrier), iargs, ip, NULL);
 #endif
 #ifdef MONO_ARCH_SOFT_FLOAT
-                               } else if (mono_type_to_stind (field->type) == CEE_STIND_R4) {
+                               } else if (mini_type_to_stind (cfg, field->type) == CEE_STIND_R4) {
                                        NEW_ICONST (cfg, offset_ins, foffset);
                                        MONO_INST_NEW (cfg, ins, OP_PADD);
                                        ins->cil_code = ip;
@@ -6168,7 +6299,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        ins->inst_right = offset_ins;
                                        ins->type = STACK_MP;
 
-                                       MONO_INST_NEW (cfg, store, mono_type_to_stind (field->type));
+                                       MONO_INST_NEW (cfg, store, mini_type_to_stind (cfg, field->type));
                                        store->cil_code = ip;
                                        store->inst_left = ins;
                                        store->inst_right = sp [1];
@@ -6193,7 +6324,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) && !MONO_TYPE_ISSTRUCT (mono_method_signature (wrapper)->ret)) {
                                                costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), bblock, 
-                                                                      iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
+                                                               iargs, ip, real_offset, dont_inline, &ebblock, TRUE, shared_context);
                                                g_assert (costs > 0);
                                                      
                                                ip += 5;
@@ -6232,14 +6363,14 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                *sp++ = ins;
                                        } else {
                                                MonoInst *load;
-                                               MONO_INST_NEW (cfg, load, mono_type_to_ldind (field->type));
-                                               type_to_eval_stack_type (field->type, load);
+                                               MONO_INST_NEW (cfg, load, mini_type_to_ldind (cfg, field->type));
+                                               type_to_eval_stack_type (cfg, field->type, load);
                                                load->cil_code = ip;
                                                load->inst_left = ins;
                                                load->flags |= ins_flag;
                                                ins_flag = 0;
 #ifdef MONO_ARCH_SOFT_FLOAT
-                                               if (mono_type_to_ldind (field->type) == CEE_LDIND_R4) {
+                                               if (mini_type_to_ldind (cfg, field->type) == CEE_LDIND_R4) {
                                                        int temp;
                                                        temp = handle_load_float (cfg, bblock, ins, ip);
                                                        NEW_TEMPLOAD (cfg, *sp, temp);
@@ -6273,6 +6404,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
                                FIELD_ACCESS_FAILURE;
 
+                       if (cfg->generic_sharing_context && mono_class_check_context_used (klass, generic_context))
+                               GENERIC_SHARING_FAILURE;
+
                        g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
 
                        if ((*ip) == CEE_STSFLD)
@@ -6351,13 +6485,14 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                MonoInst *store;
                                CHECK_STACK (1);
                                sp--;
-                               MONO_INST_NEW (cfg, store, mono_type_to_stind (field->type));
+                               MONO_INST_NEW (cfg, store, mini_type_to_stind (cfg, field->type));
                                store->cil_code = ip;
                                store->inst_left = ins;
                                store->inst_right = sp [0];
                                store->flags |= ins_flag;
                                ins_flag = 0;
 
+                               /* FIXME: handle CEE_STIND_R4 */
                                if (store->opcode == CEE_STOBJ) {
                                        handle_stobj (cfg, bblock, ins, sp [0], ip, mono_class_from_mono_type (field->type), FALSE, FALSE, FALSE);
                                } else
@@ -6413,7 +6548,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        case MONO_TYPE_FNPTR:
                                        case MONO_TYPE_ARRAY:
                                                NEW_PCONST (cfg, *sp, *((gpointer *)addr));
-                                               type_to_eval_stack_type (field->type, *sp);
+                                               type_to_eval_stack_type (cfg, field->type, *sp);
                                                sp++;
                                                break;
 #endif
@@ -6436,8 +6571,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                if (!is_const) {
                                        MonoInst *load;
                                        CHECK_STACK_OVF (1);
-                                       MONO_INST_NEW (cfg, load, mono_type_to_ldind (field->type));
-                                       type_to_eval_stack_type (field->type, load);
+                                       MONO_INST_NEW (cfg, load, mini_type_to_ldind (cfg, field->type));
+                                       type_to_eval_stack_type (cfg, field->type, load);
                                        load->cil_code = ip;
                                        load->inst_left = ins;
                                        *sp++ = load;
@@ -6457,7 +6592,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        token = read32 (ip + 1);
                        klass = mini_get_class (method, token, generic_context);
                        CHECK_TYPELOAD (klass);
-                       n = mono_type_to_stind (&klass->byval_arg);
+                       n = mini_type_to_stind (cfg, &klass->byval_arg);
+                       /* FIXME: handle CEE_STIND_R4 */
                        if (n == CEE_STOBJ) {
                                handle_stobj (cfg, bblock, sp [0], sp [1], ip, klass, FALSE, FALSE, TRUE);
                        } else {
@@ -6476,6 +6612,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        break;
                case CEE_BOX: {
                        MonoInst *val;
+
                        CHECK_STACK (1);
                        --sp;
                        val = *sp;
@@ -6484,6 +6621,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        klass = mini_get_class (method, token, generic_context);
                        CHECK_TYPELOAD (klass);
 
+                       if (cfg->generic_sharing_context && mono_class_check_context_used (klass, generic_context))
+                               GENERIC_SHARING_FAILURE;
+
                        if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
                                *sp++ = val;
                                ip += 5;
@@ -6535,7 +6675,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        inline_costs += 1;
                        break;
                }
-               case CEE_NEWARR:
+               case CEE_NEWARR: {
+                       int context_used;
+
                        CHECK_STACK (1);
                        MONO_INST_NEW (cfg, ins, *ip);
                        ins->cil_code = ip;
@@ -6556,6 +6698,15 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                        klass = mini_get_class (method, token, generic_context);
                        CHECK_TYPELOAD (klass);
+
+                       if (cfg->generic_sharing_context)
+                               context_used = mono_class_check_context_used (klass, generic_context);
+                       else
+                               context_used = 0;
+
+                       if (context_used)
+                               GENERIC_SHARING_FAILURE;
+
                        ins->inst_newa_class = klass;
                        ins->inst_newa_len = *sp;
                        ins->type = STACK_OBJ;
@@ -6608,6 +6759,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        }
                        inline_costs += 1;
                        break;
+               }
                case CEE_LDLEN:
                        CHECK_STACK (1);
                        --sp;
@@ -6661,16 +6813,16 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                UNVERIFIED;
                        CHECK_OPSIZE (5);
                        token = read32 (ip + 1);
-                       klass = mono_class_get_full (image, token, generic_context);
+                       klass = mini_get_class (method, token, generic_context);
                        CHECK_TYPELOAD (klass);
                        mono_class_init (klass);
                        NEW_LDELEMA (cfg, load, sp, klass);
                        load->cil_code = ip;
-                       MONO_INST_NEW (cfg, ins, mono_type_to_ldind (&klass->byval_arg));
+                       MONO_INST_NEW (cfg, ins, mini_type_to_ldind (cfg, &klass->byval_arg));
                        ins->cil_code = ip;
                        ins->inst_left = load;
                        *sp++ = ins;
-                       type_to_eval_stack_type (&klass->byval_arg, ins);
+                       type_to_eval_stack_type (cfg, &klass->byval_arg, ins);
                        ip += 5;
                        break;
                }
@@ -6767,7 +6919,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                UNVERIFIED;
                        CHECK_OPSIZE (5);
                        token = read32 (ip + 1);
-                       klass = mono_class_get_full (image, token, generic_context);
+                       klass = mini_get_class (method, token, generic_context);
                        CHECK_TYPELOAD (klass);
                        mono_class_init (klass);
                        if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
@@ -6796,7 +6948,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                NEW_LDELEMA (cfg, load, sp, klass);
                                load->cil_code = ip;
 
-                               n = mono_type_to_stind (&klass->byval_arg);
+                               n = mini_type_to_stind (cfg, &klass->byval_arg);
+                               /* FIXME: CEE_STIND_R4 */
                                if (n == CEE_STOBJ)
                                        handle_stobj (cfg, bblock, load, sp [2], ip, klass, FALSE, FALSE, TRUE);
                                else {
@@ -6899,6 +7052,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        mono_class_init (klass);
                        ins->cil_code = ip;
 
+                       if (cfg->generic_sharing_context && mono_class_check_context_used (klass, generic_context))
+                               GENERIC_SHARING_FAILURE;
+
                        loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
                        NEW_TEMPLOADA (cfg, ins->inst_right, loc->inst_c0);
 
@@ -6929,6 +7085,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        }
                        else {
                                handle = mono_ldtoken (image, n, &handle_class, generic_context);
+                               if (cfg->generic_sharing_context &&
+                                               mono_class_check_context_used (handle_class, generic_context))
+                                       GENERIC_SHARING_FAILURE;
                        }
                        if (!handle)
                                goto load_error;
@@ -6938,6 +7097,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                int temp;
                                MonoInst *res, *store, *addr, *vtvar, *iargs [3];
 
+                               GENERIC_SHARING_FAILURE;
+
                                vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
 
                                NEW_IMAGECONST (cfg, iargs [0], image);
@@ -7277,6 +7438,16 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                bblock->out_of_line = TRUE;
                                ip += 2;
                                break;
+                       case CEE_MONO_TLS:
+                               CHECK_STACK_OVF (1);
+                               CHECK_OPSIZE (6);
+                               MONO_INST_NEW (cfg, ins, OP_TLS_GET);
+                               ins->inst_offset = (gint32)read32 (ip + 2);
+                               ins->cil_code = ip;
+                               ins->type = STACK_PTR;
+                               *sp++ = ins;
+                               ip += 6;
+                               break;
                        default:
                                g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
                                break;
@@ -7356,6 +7527,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        }
                        case CEE_LDFTN: {
                                MonoInst *argconst;
+                               MonoMethod *cil_method;
                                int temp;
 
                                CHECK_STACK_OVF (1);
@@ -7366,6 +7538,12 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        goto load_error;
                                mono_class_init (cmethod->klass);
 
+                               if (cfg->generic_sharing_context && mono_method_check_context_used (cmethod, generic_context))
+                                       GENERIC_SHARING_FAILURE;
+
+                               cil_method = cmethod;
+                               if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
+                                       METHOD_ACCESS_FAILURE;
                                if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
                                        if (check_linkdemand (cfg, method, cmethod, bblock, ip))
                                                INLINE_FAILURE;
@@ -7400,6 +7578,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        goto load_error;
                                mono_class_init (cmethod->klass);
 
+                               if (cfg->generic_sharing_context && mono_method_check_context_used (cmethod, generic_context))
+                                       GENERIC_SHARING_FAILURE;
+
                                if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
                                        if (check_linkdemand (cfg, method, cmethod, bblock, ip))
                                                INLINE_FAILURE;
@@ -7583,6 +7764,10 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                token = read32 (ip + 2);
                                klass = mini_get_class (method, token, generic_context);
                                CHECK_TYPELOAD (klass);
+
+                               if (cfg->generic_sharing_context && mono_class_check_context_used (klass, generic_context))
+                                       GENERIC_SHARING_FAILURE;
+
                                if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
                                        MonoInst *store, *load;
                                        NEW_PCONST (cfg, load, NULL);
@@ -7616,11 +7801,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                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->backend.size = n;
+                                       NEW_MEMCPY (cfg, copy, sp [0], sp [1], n, 0);
                                        MONO_ADD_INS (bblock, copy);
                                        ip += 2;
                                        break;
@@ -7678,6 +7859,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                break;
                        }
                        case CEE_SIZEOF:
+                               GENERIC_SHARING_FAILURE;
+
                                CHECK_STACK_OVF (1);
                                CHECK_OPSIZE (6);
                                token = read32 (ip + 2);
@@ -8860,7 +9043,12 @@ mono_thread_abort (MonoObject *obj)
        /* handle_remove should be eventually called for this thread, too
        g_free (jit_tls);*/
 
-       mono_thread_exit ();
+       if ((mono_runtime_unhandled_exception_policy_get () == MONO_UNHANLED_POLICY_LEGACY) ||
+                       (obj->vtable->klass == mono_defaults.threadabortexception_class)) {
+               mono_thread_exit ();
+       } else {
+               exit (mono_environment_exitcode_get ());
+       }
 }
 
 static void*
@@ -9024,6 +9212,20 @@ mono_patch_info_hash (gconstpointer data)
        case MONO_PATCH_INFO_LDTOKEN:
        case MONO_PATCH_INFO_DECLSEC:
                return (ji->type << 8) | ji->data.token->token;
+       case MONO_PATCH_INFO_VTABLE:
+       case MONO_PATCH_INFO_CLASS:
+       case MONO_PATCH_INFO_IID:
+       case MONO_PATCH_INFO_ADJUSTED_IID:
+               return (ji->type << 8) | (gssize)ji->data.klass;
+       case MONO_PATCH_INFO_FIELD:
+       case MONO_PATCH_INFO_SFLDA:
+               return (ji->type << 8) | (gssize)ji->data.field;
+       case MONO_PATCH_INFO_METHODCONST:
+       case MONO_PATCH_INFO_METHOD:
+       case MONO_PATCH_INFO_METHOD_JUMP:
+               return (ji->type << 8) | (gssize)ji->data.method;
+       case MONO_PATCH_INFO_IMAGE:
+               return (ji->type << 8) | (gssize)ji->data.image;                
        default:
                return (ji->type << 8);
        }
@@ -9934,6 +10136,7 @@ mono_compile_create_vars (MonoCompile *cfg)
 
        if (cfg->verbose_level > 2)
                g_print ("creating locals\n");
+
        for (i = 0; i < header->num_locals; ++i)
                mono_compile_create_var (cfg, header->locals [i], OP_LOCAL);
        if (cfg->verbose_level > 2)
@@ -10447,11 +10650,21 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        MonoJitInfo *jinfo;
        int dfn = 0, i, code_size_ratio;
        gboolean deadce_has_run = FALSE;
+       gboolean try_generic_shared = (opts & MONO_OPT_GSHARED) && mono_method_is_generic_sharable_impl (method);
+       MonoGenericContext *shared_context;
 
        mono_jit_stats.methods_compiled++;
        if (mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION)
                mono_profiler_method_jit (method);
 
+       if (opts & MONO_OPT_GSHARED) {
+               if (try_generic_shared)
+                       mono_stats.generics_sharable_methods++;
+               else if (mono_method_is_generic_impl (method))
+                       mono_stats.generics_unsharable_methods++;
+       }
+
+ restart_compile:
        cfg = g_new0 (MonoCompile, 1);
        cfg->method = method;
        cfg->mempool = mono_mempool_new ();
@@ -10462,6 +10675,8 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        cfg->verbose_level = mini_verbose;
        cfg->compile_aot = compile_aot;
        cfg->skip_visibility = method->skip_visibility;
+       if (try_generic_shared)
+               cfg->generic_sharing_context = (MonoGenericSharingContext*)&cfg->generic_sharing_context;
        cfg->token_info_hash = g_hash_table_new (NULL, NULL);
        if (!header) {
                cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
@@ -10484,7 +10699,19 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
         */
        mono_compile_create_vars (cfg);
 
-       if ((i = mono_method_to_ir (cfg, method, NULL, NULL, cfg->locals_start, NULL, NULL, NULL, 0, FALSE)) < 0) {
+       if (try_generic_shared)
+               shared_context = mono_make_shared_context (cfg, mono_method_get_context (method));
+       else
+               shared_context = NULL;
+
+       if ((i = mono_method_to_ir (cfg, method, NULL, NULL, cfg->locals_start, NULL, NULL, NULL, 0, FALSE, shared_context)) < 0) {
+               if (try_generic_shared && cfg->exception_type == MONO_EXCEPTION_GENERIC_SHARING_FAILED) {
+                       mono_destroy_compile (cfg);
+                       try_generic_shared = FALSE;
+                       goto restart_compile;
+               }
+               g_assert (cfg->exception_type != MONO_EXCEPTION_GENERIC_SHARING_FAILED);
+
                if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
                        mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_FAILED);
                /* cfg contains the details of the failure, so let the caller cleanup */
@@ -10715,6 +10942,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        jinfo->used_regs = cfg->used_int_regs;
        jinfo->domain_neutral = (cfg->opt & MONO_OPT_SHARED) != 0;
        jinfo->cas_inited = FALSE; /* initialization delayed at the first stalk walk using this method */
+       jinfo->generic_shared = cfg->generic_sharing_context ? 1 : 0;
 
        if (header->num_clauses) {
                int i;
@@ -10786,6 +11014,42 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        return cfg;
 }
 
+static MonoMethod*
+method_get_declaring_generic_method (MonoMethod *method)
+{
+       MonoMethodInflated *inflated;
+
+       g_assert (method->is_inflated);
+
+       inflated = (MonoMethodInflated*)method;
+
+       return inflated->declaring;
+}
+
+static MonoJitInfo*
+lookup_generic_method (MonoDomain *domain, MonoMethod *method)
+{
+       MonoMethod *open_method;
+
+       if (!mono_method_is_generic_sharable_impl (method))
+               return NULL;
+
+       open_method = method_get_declaring_generic_method (method);
+
+       return mono_domain_lookup_shared_generic (domain, open_method);
+}
+
+static MonoJitInfo*
+lookup_method (MonoDomain *domain, MonoMethod *method)
+{
+       MonoJitInfo *ji = mono_internal_hash_table_lookup (&domain->jit_code_hash, method);
+
+       if (ji != NULL)
+               return ji;
+
+       return lookup_generic_method (domain, method);
+}
+
 static gpointer
 mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, int opt)
 {
@@ -10913,16 +11177,12 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
        }
        /* this can only be set if the security manager is active */
        case MONO_EXCEPTION_SECURITY_LINKDEMAND: {
-               MonoAssembly *assembly = mono_image_get_assembly (method->klass->image);
-               MonoReflectionAssembly *refass = (MonoReflectionAssembly*) mono_assembly_get_object (target_domain, assembly);
-               MonoReflectionMethod *refmet = mono_method_get_object (target_domain, method, NULL);
                MonoSecurityManager* secman = mono_security_manager_get_methods ();
                MonoObject *exc = NULL;
-               gpointer args [3];
+               gpointer args [2];
 
                args [0] = &cfg->exception_data;
-               args [1] = refass;
-               args [2] = refmet;
+               args [1] = &method;
                mono_runtime_invoke (secman->linkdemandsecurityexception, NULL, args, &exc);
 
                mono_destroy_compile (cfg);
@@ -10939,7 +11199,7 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
        /* Check if some other thread already did the job. In this case, we can
        discard the code this thread generated. */
 
-       if ((info = mono_internal_hash_table_lookup (&target_domain->jit_code_hash, method))) {
+       if ((info = lookup_method (target_domain, 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;
@@ -10950,6 +11210,13 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
        if (code == NULL) {
                mono_internal_hash_table_insert (&target_domain->jit_code_hash, method, cfg->jit_info);
                code = cfg->native_code;
+
+               if (cfg->generic_sharing_context && mono_method_is_generic_sharable_impl (method)) {
+                       /* g_print ("inserting method %s.%s.%s\n", method->klass->name_space, method->klass->name, method->name); */
+                       mono_domain_register_shared_generic (target_domain, 
+                               method_get_declaring_generic_method (method), cfg->jit_info);
+                       mono_stats.generics_shared_methods++;
+               }
        }
 
        mono_destroy_compile (cfg);
@@ -11007,7 +11274,7 @@ mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt)
 
        mono_domain_lock (target_domain);
 
-       if ((info = mono_internal_hash_table_lookup (&target_domain->jit_code_hash, method))) {
+       if ((info = lookup_method (target_domain, method))) {
                /* We can't use a domain specific method in another domain */
                if (! ((domain != target_domain) && !info->domain_neutral)) {
                        mono_domain_unlock (target_domain);
@@ -11113,7 +11380,7 @@ mono_jit_find_compiled_method (MonoDomain *domain, MonoMethod *method)
 
        mono_domain_lock (target_domain);
 
-       if ((info = mono_internal_hash_table_lookup (&target_domain->jit_code_hash, method))) {
+       if ((info = lookup_method (target_domain, method))) {
                /* We can't use a domain specific method in another domain */
                if (! ((domain != target_domain) && !info->domain_neutral)) {
                        mono_domain_unlock (target_domain);
@@ -11759,6 +12026,28 @@ mono_jit_create_remoting_trampoline (MonoMethod *method, MonoRemotingTarget targ
        return mono_get_addr_from_ftnptr (addr);
 }
 
+#ifdef MONO_ARCH_HAVE_IMT
+static gpointer
+mini_get_imt_trampoline (void)
+{
+       static gpointer tramp = NULL;
+       if (!tramp)
+               tramp =  mono_arch_create_specific_trampoline (MONO_FAKE_IMT_METHOD, MONO_TRAMPOLINE_GENERIC, mono_get_root_domain (), NULL);
+       return tramp;
+}
+#endif
+
+#ifdef MONO_ARCH_COMMON_VTABLE_TRAMPOLINE
+static gpointer
+mini_get_vtable_trampoline (void)
+{
+       static gpointer tramp = NULL;
+       if (!tramp)
+               tramp =  mono_arch_create_specific_trampoline (MONO_FAKE_VTABLE_METHOD, MONO_TRAMPOLINE_GENERIC, mono_get_root_domain (), NULL);
+       return tramp;
+}
+#endif
+
 static void
 mini_parse_debug_options (void)
 {
@@ -11807,11 +12096,14 @@ mini_init (const char *filename, const char *runtime_version)
 
        InitializeCriticalSection (&jit_mutex);
 
-       global_codeman = mono_code_manager_new ();
+       if (!global_codeman)
+               global_codeman = mono_code_manager_new ();
        jit_icall_name_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
 
        mono_arch_cpu_init ();
 
+       mono_arch_init ();
+
        mono_init_trampolines ();
 
        mono_init_exceptions ();
@@ -11903,9 +12195,6 @@ mini_init (const char *filename, const char *runtime_version)
        mono_install_get_class_from_name (mono_aot_get_class_from_name);
        mono_install_jit_info_find_in_aot (mono_aot_find_jit_info);
 
-#ifdef MONO_ARCH_HAVE_IMT
-       mono_install_imt_thunk_builder (mono_arch_build_imt_thunk);
-#endif
        if (debug_options.collect_pagefault_stats) {
                mono_raw_buffer_set_make_unreadable (TRUE);
                mono_aot_set_make_unreadable (TRUE);
@@ -11915,6 +12204,13 @@ mini_init (const char *filename, const char *runtime_version)
                domain = mono_init_version (filename, runtime_version);
        else
                domain = mono_init_from_assembly (filename, filename);
+#ifdef MONO_ARCH_HAVE_IMT
+       mono_install_imt_thunk_builder (mono_arch_build_imt_thunk);
+       mono_install_imt_trampoline (mini_get_imt_trampoline ());
+#if MONO_ARCH_COMMON_VTABLE_TRAMPOLINE
+       mono_install_vtable_trampoline (mini_get_vtable_trampoline ());
+#endif
+#endif
        mono_icall_init ();
 
        mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info", 
@@ -12122,6 +12418,7 @@ print_jit_stats (void)
                g_print ("Locals stack size:      %ld\n", mono_jit_stats.locals_stack_size);
 
                g_print ("\nCreated object count:   %ld\n", mono_stats.new_object_count);
+               g_print ("Delegates created:      %ld\n", mono_stats.delegate_creations);
                g_print ("Initialized classes:    %ld\n", mono_stats.initialized_class_count);
                g_print ("Used classes:           %ld\n", mono_stats.used_class_count);
                g_print ("Generic vtables:        %ld\n", mono_stats.generic_vtable_count);
@@ -12138,6 +12435,10 @@ print_jit_stats (void)
                g_print ("Generics metadata size: %ld\n", mono_stats.generics_metadata_size);
                g_print ("Generics virtual invokes: %ld\n", mono_jit_stats.generic_virtual_invocations);
 
+               g_print ("Sharable generic methods: %ld\n", mono_stats.generics_sharable_methods);
+               g_print ("Unsharable generic methods: %ld\n", mono_stats.generics_unsharable_methods);
+               g_print ("Shared generic methods: %ld\n", mono_stats.generics_shared_methods);
+
                g_print ("Dynamic code allocs:    %ld\n", mono_stats.dynamic_code_alloc_count);
                g_print ("Dynamic code bytes:     %ld\n", mono_stats.dynamic_code_bytes_count);
                g_print ("Dynamic code frees:     %ld\n", mono_stats.dynamic_code_frees_count);
@@ -12201,7 +12502,7 @@ mini_cleanup (MonoDomain *domain)
 
        mono_domain_free (domain, TRUE);
 
-       mono_debug_cleanup ();
+       mono_debugger_cleanup ();
 
        mono_code_manager_destroy (global_codeman);
        g_hash_table_destroy (jit_icall_name_hash);
@@ -12209,12 +12510,17 @@ mini_cleanup (MonoDomain *domain)
                g_hash_table_destroy (class_init_hash_addr);
        g_free (emul_opcode_map);
 
+       mono_arch_cleanup ();
+
        mono_cleanup ();
 
        mono_trace_cleanup ();
 
        mono_counters_dump (-1, stdout);
 
+       if (mono_inject_async_exc_method)
+               mono_method_desc_free (mono_inject_async_exc_method);
+
        TlsFree(mono_jit_tls_id);
 
        DeleteCriticalSection (&jit_mutex);