Fix support for MONO_PATCH_INFO_GSHAREDVT_CALL in mono_patch_info_dup_mp ().
[mono.git] / mono / mini / mini.c
index 0514777d4bb79d52bb492bea326d306d28ca7d10..01576ad569872f7facbd768c0d41c8a9fc608479 100644 (file)
@@ -293,7 +293,10 @@ get_method_from_ip (void *ip)
        MonoDomain *domain = mono_domain_get ();
        MonoDebugSourceLocation *location;
        FindTrampUserData user_data;
-       
+
+       if (!domain)
+               domain = mono_get_root_domain ();
+
        ji = mono_jit_info_table_find (domain, ip);
        if (!ji) {
                user_data.ip = ip;
@@ -364,6 +367,8 @@ mono_print_method_from_ip (void *ip)
        MonoDomain *domain = mono_domain_get ();
        MonoDomain *target_domain = mono_domain_get ();
        FindTrampUserData user_data;
+       MonoGenericSharingContext*gsctx;
+       const char *shared_type;
        
        ji = mini_jit_info_table_find (domain, ip, &target_domain);
        if (!ji) {
@@ -385,7 +390,16 @@ mono_print_method_from_ip (void *ip)
        method = mono_method_full_name (ji->method, TRUE);
        source = mono_debug_lookup_source_location (ji->method, (guint32)((guint8*)ip - (guint8*)ji->code_start), target_domain);
 
-       g_print ("IP %p at offset 0x%x of method %s (%p %p)[domain %p - %s]\n", ip, (int)((char*)ip - (char*)ji->code_start), method, ji->code_start, (char*)ji->code_start + ji->code_size, target_domain, target_domain->friendly_name);
+       gsctx = mono_jit_info_get_generic_sharing_context (ji);
+       shared_type = "";
+       if (gsctx) {
+               if (gsctx->var_is_vt || gsctx->mvar_is_vt)
+                       shared_type = "gsharedvt ";
+               else
+                       shared_type = "gshared ";
+       }
+
+       g_print ("IP %p at offset 0x%x of %smethod %s (%p %p)[domain %p - %s]\n", ip, (int)((char*)ip - (char*)ji->code_start), shared_type, method, ji->code_start, (char*)ji->code_start + ji->code_size, target_domain, target_domain->friendly_name);
 
        if (source)
                g_print ("%s:%d\n", source->source_file, source->row);
@@ -598,6 +612,35 @@ mono_tramp_info_free (MonoTrampInfo *info)
        g_free (info);
 }
 
+G_GNUC_UNUSED static void
+break_count (void)
+{
+}
+
+/*
+ * Runtime debugging tool, use if (debug_count ()) <x> else <y> to do <x> the first COUNT times, then do <y> afterwards.
+ * Set a breakpoint in break_count () to break the last time <x> is done.
+ */
+G_GNUC_UNUSED gboolean
+mono_debug_count (void)
+{
+       static int count = 0;
+       count ++;
+
+       if (!getenv ("COUNT"))
+               return TRUE;
+
+       if (count == atoi (getenv ("COUNT"))) {
+               break_count ();
+       }
+
+       if (count > atoi (getenv ("COUNT"))) {
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
 #define MONO_INIT_VARINFO(vi,id) do { \
        (vi)->range.first_use.pos.bid = 0xffff; \
        (vi)->reg = -1; \
@@ -830,12 +873,10 @@ handle_enum:
                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);
-               return OP_STORE_MEMBASE_REG;
+               if (mini_type_var_is_vt (cfg, type))
+                       return OP_STOREV_MEMBASE;
+               else
+                       return OP_STORE_MEMBASE_REG;
        default:
                g_error ("unknown type 0x%02x in type_to_store_membase", type->type);
        }
@@ -896,12 +937,11 @@ mono_type_to_load_membase (MonoCompile *cfg, MonoType *type)
                break;
        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);
-               return OP_LOAD_MEMBASE;
+               if (mini_type_var_is_vt (cfg, type))
+                       return OP_LOADV_MEMBASE;
+               else
+                       return OP_LOAD_MEMBASE;
        default:
                g_error ("unknown type 0x%02x in type_to_load_membase", type->type);
        }
@@ -912,12 +952,12 @@ 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;
+               if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
+                       if (mini_type_var_is_vt (cfg, type))
+                               return CEE_LDOBJ;
+                       else
+                               return CEE_LDIND_REF;
+               }
        }
        return mono_type_to_ldind (type);
 }
@@ -926,12 +966,12 @@ 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;
+               if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
+                       if (mini_type_var_is_vt (cfg, type))
+                               return CEE_STOBJ;
+                       else
+                               return CEE_STIND_REF;
+               }
        }
        return mono_type_to_stind (type);
 }
@@ -1121,6 +1161,9 @@ mono_compile_create_var_for_vreg (MonoCompile *cfg, MonoType *type, int opcode,
        inst->backend.is_pinvoke = 0;
        inst->dreg = vreg;
 
+       if (inst->klass->exception_type)
+               mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
+
        if (cfg->compute_gc_maps) {
                if (type->byref) {
                        mono_mark_vreg_as_mp (cfg, vreg);
@@ -1714,18 +1757,22 @@ mono_allocate_stack_slots2 (MonoCompile *cfg, gboolean backward, guint32 *stack_
                vmv = current;
                inst = cfg->varinfo [vmv->idx];
 
+               t = mono_type_get_underlying_type (inst->inst_vtype);
+               if (cfg->gsharedvt && mini_is_gsharedvt_variable_type (cfg, t))
+                       t = mini_get_gsharedvt_alloc_type_for_type (cfg, t);
+
                /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
                * pinvoke wrappers when they call functions returning structures */
-               if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF) {
-                       size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), &align);
+               if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (t) && t->type != MONO_TYPE_TYPEDBYREF) {
+                       size = mono_class_native_size (mono_class_from_mono_type (t), &align);
                }
                else {
                        int ialign;
 
-                       size = mono_type_size (inst->inst_vtype, &ialign);
+                       size = mono_type_size (t, &ialign);
                        align = ialign;
 
-                       if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (inst->inst_vtype)))
+                       if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (t)))
                                align = 16;
                }
 
@@ -1733,7 +1780,6 @@ mono_allocate_stack_slots2 (MonoCompile *cfg, gboolean backward, guint32 *stack_
                if (cfg->disable_reuse_stack_slots)
                        reuse_slot = FALSE;
 
-               t = mono_type_get_underlying_type (inst->inst_vtype);
                switch (t->type) {
                case MONO_TYPE_GENERICINST:
                        if (!mono_type_generic_inst_is_valuetype (t)) {
@@ -2007,17 +2053,24 @@ mono_allocate_stack_slots (MonoCompile *cfg, gboolean backward, guint32 *stack_s
                vmv = l->data;
                inst = cfg->varinfo [vmv->idx];
 
+               t = mono_type_get_underlying_type (inst->inst_vtype);
+               if (cfg->gsharedvt && mini_is_gsharedvt_variable_type (cfg, t))
+                       t = mini_get_gsharedvt_alloc_type_for_type (cfg, t);
+
                /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
                * pinvoke wrappers when they call functions returning structures */
-               if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF) {
-                       size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), &align);
+               if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (t) && t->type != MONO_TYPE_TYPEDBYREF) {
+                       size = mono_class_native_size (mono_class_from_mono_type (t), &align);
                } else {
                        int ialign;
 
-                       size = mono_type_size (inst->inst_vtype, &ialign);
+                       size = mono_type_size (t, &ialign);
                        align = ialign;
 
-                       if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (inst->inst_vtype)))
+                       if (mono_class_from_mono_type (t)->exception_type)
+                               mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
+
+                       if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (t)))
                                align = 16;
                }
 
@@ -2025,7 +2078,6 @@ mono_allocate_stack_slots (MonoCompile *cfg, gboolean backward, guint32 *stack_s
                if (cfg->disable_reuse_stack_slots)
                        reuse_slot = FALSE;
 
-               t = mono_type_get_underlying_type (inst->inst_vtype);
                if (t->byref) {
                        slot_info = &scalar_stack_slots [MONO_TYPE_I];
                } else {
@@ -2078,9 +2130,13 @@ mono_allocate_stack_slots (MonoCompile *cfg, gboolean backward, guint32 *stack_s
                                if (cfg->disable_reuse_ref_stack_slots)
                                        reuse_slot = FALSE;
                                break;
-
+                       case MONO_TYPE_VAR:
+                       case MONO_TYPE_MVAR:
+                               slot_info = &scalar_stack_slots [t->type];
+                               break;
                        default:
                                slot_info = &scalar_stack_slots [t->type];
+                               break;
                        }
                }
 
@@ -2571,10 +2627,17 @@ mono_set_lmf_addr (gpointer lmf_addr)
 #endif
 }
 
-/* Called by native->managed wrappers */
-void
+/*
+ * mono_jit_thread_attach:
+ *
+ * Called by native->managed wrappers. Returns the original domain which needs to be
+ * restored, or NULL.
+ */
+MonoDomain*
 mono_jit_thread_attach (MonoDomain *domain)
 {
+       MonoDomain *orig;
+
        if (!domain)
                /* 
                 * Happens when called from AOTed code which is only used in the root
@@ -2594,10 +2657,21 @@ mono_jit_thread_attach (MonoDomain *domain)
                mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background);
        }
 #endif
-       if (mono_domain_get () != domain)
-               mono_domain_set (domain, TRUE);
+       orig = mono_domain_get ();
+       if (orig != domain)
+               mono_domain_set (domain, TRUE);
+
+       return orig != domain ? orig : NULL;
 }      
 
+/* Called by native->managed wrappers */
+void
+mono_jit_set_domain (MonoDomain *domain)
+{
+       if (domain)
+               mono_domain_set (domain, TRUE);
+}
+
 /**
  * mono_thread_abort:
  * @obj: exception object
@@ -2616,16 +2690,7 @@ mono_thread_abort (MonoObject *obj)
                        (obj->vtable->klass == mono_defaults.threadabortexception_class)) {
                mono_thread_exit ();
        } else {
-               MonoObject *other = NULL;
-               MonoString *str = mono_object_to_string (obj, &other);
-               if (str) {
-                       char *msg = mono_string_to_utf8 (str);
-                       fprintf (stderr, "[ERROR] FATAL UNHANDLED EXCEPTION: %s\n", msg);
-                       fflush (stderr);
-                       g_free (msg);
-               }
-
-               exit (mono_environment_exitcode_get ());
+               mono_invoke_unhandled_exception_hook (obj);
        }
 }
 
@@ -2654,14 +2719,13 @@ setup_jit_tls_data (gpointer stack_start, gpointer abort_func)
 #if defined(MONO_HAVE_FAST_TLS) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
        /* jit_tls->lmf is unused */
        MONO_FAST_TLS_SET (mono_lmf, lmf);
-       mono_set_lmf_addr (&mono_lmf);
+       mono_set_lmf_addr (MONO_FAST_TLS_ADDR (mono_lmf));
 #else
        mono_set_lmf_addr (&jit_tls->lmf);
 
        jit_tls->lmf = lmf;
 #endif
 
-       mono_arch_setup_jit_tls_data (jit_tls);
        mono_setup_altstack (jit_tls);
 
        return jit_tls;
@@ -2782,6 +2846,12 @@ mono_get_thread_intrinsic (MonoCompile* cfg)
        return mono_create_tls_get (cfg, mono_thread_get_tls_offset ());
 }
 
+MonoInst*
+mono_get_lmf_intrinsic (MonoCompile* cfg)
+{
+       return mono_create_tls_get (cfg, mono_get_lmf_tls_offset ());
+}
+
 void
 mono_add_patch_info (MonoCompile *cfg, int ip, MonoJumpInfoType type, gconstpointer target)
 {
@@ -2852,6 +2922,10 @@ mono_patch_info_dup_mp (MonoMemPool *mp, MonoJumpInfo *patch_info)
                memcpy (res->data.rgctx_entry, patch_info->data.rgctx_entry, sizeof (MonoJumpInfoRgctxEntry));
                res->data.rgctx_entry->data = mono_patch_info_dup_mp (mp, res->data.rgctx_entry->data);
                break;
+       case MONO_PATCH_INFO_GSHAREDVT_CALL:
+               res->data.gsharedvt = mono_mempool_alloc (mp, sizeof (MonoJumpInfoGSharedVtCall));
+               memcpy (res->data.gsharedvt, patch_info->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall));
+               break;
        default:
                break;
        }
@@ -2888,6 +2962,8 @@ mono_patch_info_hash (gconstpointer data)
        case MONO_PATCH_INFO_SFLDA:
        case MONO_PATCH_INFO_SEQ_POINT_INFO:
                return (ji->type << 8) | (gssize)ji->data.target;
+       case MONO_PATCH_INFO_GSHAREDVT_CALL:
+               return (ji->type << 8) | (gssize)ji->data.gsharedvt->method;
        default:
                return (ji->type << 8);
        }
@@ -3068,7 +3144,7 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
                break;
        }
        case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
-               target = mono_create_delegate_trampoline (patch_info->data.klass);
+               target = mono_create_delegate_trampoline (domain, patch_info->data.klass);
                break;
        case MONO_PATCH_INFO_SFLDA: {
                MonoVTable *vtable = mono_class_vtable (domain, patch_info->data.field->parent);
@@ -3145,10 +3221,16 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
        case MONO_PATCH_INFO_ICALL_ADDR:
                /* run_cctors == 0 -> AOT */
                if (patch_info->data.method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
+                       const char *exc_class;
+                       const char *exc_arg;
+
                        if (run_cctors) {
-                               target = mono_lookup_pinvoke_call (patch_info->data.method, NULL, NULL);
-                               if (!target)
+                               target = mono_lookup_pinvoke_call (patch_info->data.method, &exc_class, &exc_arg);
+                               if (!target) {
+                                       if (mono_aot_only)
+                                               mono_raise_exception (mono_exception_from_name_msg (mono_defaults.corlib, "System", exc_class, exc_arg));
                                        g_error ("Unable to resolve pinvoke method '%s' Re-run with MONO_LOG_LEVEL=debug for more information.\n", mono_method_full_name (patch_info->data.method, TRUE));
+                               }
                        } else {
                                target = NULL;
                        }
@@ -3189,15 +3271,25 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
 
                switch (entry->data->type) {
                case MONO_PATCH_INFO_CLASS:
-                       slot = mono_method_lookup_or_register_other_info (entry->method, entry->in_mrgctx, &entry->data->data.klass->byval_arg, entry->info_type, mono_method_get_context (entry->method));
+                       slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, &entry->data->data.klass->byval_arg, entry->info_type, mono_method_get_context (entry->method));
                        break;
                case MONO_PATCH_INFO_METHOD:
                case MONO_PATCH_INFO_METHODCONST:
-                       slot = mono_method_lookup_or_register_other_info (entry->method, entry->in_mrgctx, entry->data->data.method, entry->info_type, mono_method_get_context (entry->method));
+                       slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, entry->data->data.method, entry->info_type, mono_method_get_context (entry->method));
                        break;
                case MONO_PATCH_INFO_FIELD:
-                       slot = mono_method_lookup_or_register_other_info (entry->method, entry->in_mrgctx, entry->data->data.field, entry->info_type, mono_method_get_context (entry->method));
+                       slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, entry->data->data.field, entry->info_type, mono_method_get_context (entry->method));
+                       break;
+               case MONO_PATCH_INFO_SIGNATURE:
+                       slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, entry->data->data.sig, entry->info_type, mono_method_get_context (entry->method));
                        break;
+               case MONO_PATCH_INFO_GSHAREDVT_CALL: {
+                       MonoJumpInfoGSharedVtCall *call_info = mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
+
+                       memcpy (call_info, entry->data->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall));
+                       slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, call_info, entry->info_type, mono_method_get_context (entry->method));
+                       break;
+               }
                default:
                        g_assert_not_reached ();
                        break;
@@ -3259,6 +3351,26 @@ mono_add_seq_point (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins, int nat
        bb->last_seq_point = ins;
 }
 
+void
+mono_add_var_location (MonoCompile *cfg, MonoInst *var, gboolean is_reg, int reg, int offset, int from, int to)
+{
+       MonoDwarfLocListEntry *entry = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoDwarfLocListEntry));
+
+       if (is_reg)
+               g_assert (offset == 0);
+
+       entry->is_reg = is_reg;
+       entry->reg = reg;
+       entry->offset = offset;
+       entry->from = from;
+       entry->to = to;
+
+       if (var == cfg->args [0])
+               cfg->this_loclist = g_slist_append_mempool (cfg->mempool, cfg->this_loclist, entry);
+       else if (var == cfg->rgctx_var)
+               cfg->rgctx_loclist = g_slist_append_mempool (cfg->mempool, cfg->rgctx_loclist, entry);
+}
+
 #ifndef DISABLE_JIT
 
 static void
@@ -3522,6 +3634,29 @@ mono_save_seq_point_info (MonoCompile *cfg)
 
                        last = ins;
                }
+
+               if (bb->last_ins && bb->last_ins->opcode == OP_ENDFINALLY) {
+                       MonoBasicBlock *bb2;
+                       MonoInst *endfinally_seq_point = NULL;
+
+                       /*
+                        * The ENDFINALLY branches are not represented in the cfg, so link it with all seq points starting bbs.
+                        */
+                       l = g_slist_last (bb->seq_points);
+                       g_assert (l);
+                       endfinally_seq_point = l->data;
+
+                       for (bb2 = cfg->bb_entry; bb2; bb2 = bb2->next_bb) {
+                               GSList *l = g_slist_last (bb2->seq_points);
+
+                               if (l) {
+                                       MonoInst *ins = l->data;
+
+                                       if (!(ins->inst_imm == METHOD_ENTRY_IL_OFFSET || ins->inst_imm == METHOD_EXIT_IL_OFFSET) && ins != endfinally_seq_point)
+                                               next [endfinally_seq_point->backend.size] = g_slist_append (next [endfinally_seq_point->backend.size], GUINT_TO_POINTER (ins->backend.size));
+                               }
+                       }
+               }
        }
 
        if (cfg->verbose_level > 2) {
@@ -3537,10 +3672,10 @@ mono_save_seq_point_info (MonoCompile *cfg)
                sp->next = g_new (int, sp->next_len);
                j = 0;
                if (cfg->verbose_level > 2 && next [i]) {
-                       printf ("\t0x%x ->", sp->il_offset);
+                       printf ("\tIL0x%x ->", sp->il_offset);
                        for (l = next [i]; l; l = l->next) {
                                next_index = GPOINTER_TO_UINT (l->data);
-                               printf (" 0x%x", info->seq_points [next_index].il_offset);
+                               printf (" IL0x%x", info->seq_points [next_index].il_offset);
                        }
                        printf ("\n");
                }
@@ -3800,6 +3935,34 @@ mono_handle_out_of_line_bblock (MonoCompile *cfg)
        }
 }
 
+#endif /* #ifndef DISABLE_JIT */
+
+static MonoJitInfo*
+create_jit_info_for_trampoline (MonoMethod *wrapper, MonoTrampInfo *info)
+{
+       MonoDomain *domain = mono_get_root_domain ();
+       MonoJitInfo *jinfo;
+       guint8 *uw_info;
+       guint32 info_len;
+
+       if (info->uw_info) {
+               uw_info = info->uw_info;
+               info_len = info->uw_info_len;
+       } else {
+               uw_info = mono_unwind_ops_encode (info->unwind_ops, &info_len);
+       }
+
+       jinfo = mono_domain_alloc0 (domain, MONO_SIZEOF_JIT_INFO);
+       jinfo->method = wrapper;
+       jinfo->code_start = info->code;
+       jinfo->code_size = info->code_size;
+       jinfo->used_regs = mono_cache_unwind_info (uw_info, info_len);
+
+       return jinfo;
+}
+
+#ifndef DISABLE_JIT
+
 static MonoJitInfo*
 create_jit_info (MonoCompile *cfg, MonoMethod *method_to_compile)
 {
@@ -3808,7 +3971,7 @@ create_jit_info (MonoCompile *cfg, MonoMethod *method_to_compile)
        MonoJitInfo *jinfo;
        int num_clauses;
        int generic_info_size, arch_eh_info_size = 0;
-       int holes_size = 0, num_holes = 0;
+       int holes_size = 0, num_holes = 0, cas_size = 0;
        guint32 stack_size = 0;
 
        g_assert (method_to_compile == cfg->method);
@@ -3828,7 +3991,7 @@ create_jit_info (MonoCompile *cfg, MonoMethod *method_to_compile)
                 * mono_arch_get_argument_info () is not signal safe.
                 */
                arg_info = g_newa (MonoJitArgumentInfo, sig->param_count + 1);
-               stack_size = mono_arch_get_argument_info (sig, sig->param_count, arg_info);
+               stack_size = mono_arch_get_argument_info (cfg->generic_sharing_context, sig, sig->param_count, arg_info);
 
                if (stack_size)
                        arch_eh_info_size = sizeof (MonoArchEHJitInfo);
@@ -3852,6 +4015,10 @@ create_jit_info (MonoCompile *cfg, MonoMethod *method_to_compile)
                        printf ("Number of try block holes %d\n", num_holes);
        }
 
+       if (mono_method_has_declsec (cfg->method_to_register)) {
+               cas_size = sizeof (MonoMethodCasInfo);
+       }
+
        if (COMPILE_LLVM (cfg))
                num_clauses = cfg->llvm_ex_info_len;
        else
@@ -3859,11 +4026,11 @@ create_jit_info (MonoCompile *cfg, MonoMethod *method_to_compile)
 
        if (cfg->method->dynamic) {
                jinfo = g_malloc0 (MONO_SIZEOF_JIT_INFO + (num_clauses * sizeof (MonoJitExceptionInfo)) +
-                               generic_info_size + holes_size + arch_eh_info_size);
+                               generic_info_size + holes_size + arch_eh_info_size + cas_size);
        } else {
                jinfo = mono_domain_alloc0 (cfg->domain, MONO_SIZEOF_JIT_INFO +
                                (num_clauses * sizeof (MonoJitExceptionInfo)) +
-                               generic_info_size + holes_size + arch_eh_info_size);
+                               generic_info_size + holes_size + arch_eh_info_size + cas_size);
        }
 
        jinfo->method = cfg->method_to_register;
@@ -3871,21 +4038,26 @@ create_jit_info (MonoCompile *cfg, MonoMethod *method_to_compile)
        jinfo->code_size = cfg->code_len;
        jinfo->used_regs = cfg->used_int_regs;
        jinfo->domain_neutral = (cfg->opt & MONO_OPT_SHARED) != 0;
-       jinfo->cas_inited = FALSE; /* initialization delayed at the first stalk walk using this method */
        jinfo->num_clauses = num_clauses;
+
        if (COMPILE_LLVM (cfg))
                jinfo->from_llvm = TRUE;
 
        if (cfg->generic_sharing_context) {
                MonoInst *inst;
                MonoGenericJitInfo *gi;
+               GSList *loclist = NULL;
 
                jinfo->has_generic_jit_info = 1;
 
                gi = mono_jit_info_get_generic_jit_info (jinfo);
                g_assert (gi);
 
-               gi->generic_sharing_context = cfg->generic_sharing_context;
+               if (cfg->method->dynamic)
+                       gi->generic_sharing_context = g_new0 (MonoGenericSharingContext, 1);
+               else
+                       gi->generic_sharing_context = mono_domain_alloc0 (cfg->domain, sizeof (MonoGenericSharingContext));
+               memcpy (gi->generic_sharing_context, cfg->generic_sharing_context, sizeof (MonoGenericSharingContext));
 
                if ((method_to_compile->flags & METHOD_ATTRIBUTE_STATIC) ||
                                mini_method_get_context (method_to_compile)->method_inst ||
@@ -3901,8 +4073,27 @@ create_jit_info (MonoCompile *cfg, MonoMethod *method_to_compile)
                        inst = cfg->rgctx_var;
                        if (!COMPILE_LLVM (cfg))
                                g_assert (inst->opcode == OP_REGOFFSET);
+                       loclist = cfg->rgctx_loclist;
                } else {
                        inst = cfg->args [0];
+                       loclist = cfg->this_loclist;
+               }
+
+               if (loclist) {
+                       /* Needed to handle async exceptions */
+                       GSList *l;
+                       int i;
+
+                       gi->nlocs = g_slist_length (loclist);
+                       if (cfg->method->dynamic)
+                               gi->locations = g_malloc0 (gi->nlocs * sizeof (MonoDwarfLocListEntry));
+                       else
+                               gi->locations = mono_domain_alloc0 (cfg->domain, gi->nlocs * sizeof (MonoDwarfLocListEntry));
+                       i = 0;
+                       for (l = loclist; l; l = l->next) {
+                               memcpy (&(gi->locations [i]), l->data, sizeof (MonoDwarfLocListEntry));
+                               i ++;
+                       }
                }
 
                if (COMPILE_LLVM (cfg)) {
@@ -3970,6 +4161,10 @@ create_jit_info (MonoCompile *cfg, MonoMethod *method_to_compile)
                info->stack_size = stack_size;
        }
 
+       if (cas_size) {
+               jinfo->has_cas_info = 1;
+       }
+
        if (COMPILE_LLVM (cfg)) {
                if (num_clauses)
                        memcpy (&jinfo->clauses [0], &cfg->llvm_ex_info [0], num_clauses * sizeof (MonoJitExceptionInfo));
@@ -4083,18 +4278,75 @@ create_jit_info (MonoCompile *cfg, MonoMethod *method_to_compile)
 }
 #endif
 
+static MonoType*
+get_gsharedvt_type (MonoType *t)
+{
+       MonoGenericParam *par = t->data.generic_param;
+       MonoType *res;
+
+       /* 
+        * Create an anonymous gparam with a different serial so normal gshared and gsharedvt methods have
+        * a different instantiation.
+        */
+       g_assert (mono_generic_param_info (par));
+       par = g_memdup (par, sizeof (MonoGenericParamFull));
+       par->owner = NULL;
+       // FIXME:
+       par->image = mono_defaults.corlib;
+       par->serial = 1;
+       res = mono_metadata_type_dup (NULL, t);
+       res->data.generic_param = par;
+
+       return res;
+}
+
+static gboolean
+is_gsharedvt_type (MonoType *t)
+{
+       return (t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR) && t->data.generic_param->serial == 1;
+}
+
+/* Return whenever METHOD is a gsharedvt method */
+static gboolean
+is_gsharedvt_method (MonoMethod *method)
+{
+       MonoGenericContext *context;
+       MonoGenericInst *inst;
+       int i;
+
+       if (!method->is_inflated)
+               return FALSE;
+       context = mono_method_get_context (method);
+       inst = context->class_inst;
+       if (inst) {
+               for (i = 0; i < inst->type_argc; ++i)
+                       if (is_gsharedvt_type (inst->type_argv [i]))
+                               return TRUE;
+       }
+       inst = context->method_inst;
+       if (inst) {
+               for (i = 0; i < inst->type_argc; ++i)
+                       if (is_gsharedvt_type (inst->type_argv [i]))
+                               return TRUE;
+       }
+       return FALSE;
+}
+
 /*
- * mini_get_shared_method:
+ * mini_get_shared_method_full:
  *
  *   Return the method which is actually compiled/registered when doing generic sharing.
+ * If ALL_VT is true, return the shared method belonging to an all-vtype instantiation.
+ * If IS_GSHAREDVT is true, treat METHOD as a gsharedvt method even if it fails some constraints.
  */
 MonoMethod*
-mini_get_shared_method (MonoMethod *method)
+mini_get_shared_method_full (MonoMethod *method, gboolean all_vt, gboolean is_gsharedvt)
 {
        MonoGenericContext shared_context;
        MonoMethod *declaring_method, *res;
        int i;
        gboolean partial = FALSE;
+       gboolean gsharedvt = FALSE;
 
        if (method->is_generic || method->klass->generic_container)
                declaring_method = method;
@@ -4106,12 +4358,15 @@ mini_get_shared_method (MonoMethod *method)
        else
                shared_context = declaring_method->klass->generic_container->context;
 
-       /* Handle partial sharing */
-       if (method != declaring_method && method->is_inflated && !mono_method_is_generic_sharable_impl_full (method, FALSE, FALSE)) {
+       /* Handle gsharedvt/partial sharing */
+       if ((method != declaring_method && method->is_inflated && !mono_method_is_generic_sharable_impl_full (method, FALSE, FALSE, TRUE)) ||
+               is_gsharedvt || mini_is_gsharedvt_sharable_method (method)) {
                MonoGenericContext *context = mono_method_get_context (method);
                MonoGenericInst *inst;
                MonoType **type_argv;
 
+               gsharedvt = is_gsharedvt || mini_is_gsharedvt_sharable_method (method);
+
                /* 
                 * Create the shared context by replacing the ref type arguments with
                 * type parameters, and keeping the rest.
@@ -4121,8 +4376,10 @@ mini_get_shared_method (MonoMethod *method)
                if (inst) {
                        type_argv = g_new0 (MonoType*, inst->type_argc);
                        for (i = 0; i < inst->type_argc; ++i) {
-                               if (MONO_TYPE_IS_REFERENCE (inst->type_argv [i]) || inst->type_argv [i]->type == MONO_TYPE_VAR || inst->type_argv [i]->type == MONO_TYPE_MVAR)
+                               if (!all_vt && (MONO_TYPE_IS_REFERENCE (inst->type_argv [i]) || inst->type_argv [i]->type == MONO_TYPE_VAR || inst->type_argv [i]->type == MONO_TYPE_MVAR))
                                        type_argv [i] = shared_context.class_inst->type_argv [i];
+                               else if (gsharedvt)
+                                       type_argv [i] = get_gsharedvt_type (shared_context.class_inst->type_argv [i]);
                                else
                                        type_argv [i] = inst->type_argv [i];
                        }
@@ -4135,8 +4392,10 @@ mini_get_shared_method (MonoMethod *method)
                if (inst) {
                        type_argv = g_new0 (MonoType*, inst->type_argc);
                        for (i = 0; i < inst->type_argc; ++i) {
-                               if (MONO_TYPE_IS_REFERENCE (inst->type_argv [i]) || inst->type_argv [i]->type == MONO_TYPE_VAR || inst->type_argv [i]->type == MONO_TYPE_MVAR)
+                               if (!all_vt && (MONO_TYPE_IS_REFERENCE (inst->type_argv [i]) || inst->type_argv [i]->type == MONO_TYPE_VAR || inst->type_argv [i]->type == MONO_TYPE_MVAR))
                                        type_argv [i] = shared_context.method_inst->type_argv [i];
+                               else if (gsharedvt)
+                                       type_argv [i] = get_gsharedvt_type (shared_context.method_inst->type_argv [i]);
                                else
                                        type_argv [i] = inst->type_argv [i];
                        }
@@ -4154,6 +4413,54 @@ mini_get_shared_method (MonoMethod *method)
        return res;
 }
 
+MonoMethod*
+mini_get_shared_method (MonoMethod *method)
+{
+       return mini_get_shared_method_full (method, FALSE, FALSE);
+}
+
+static void
+mini_init_gsctx_full (MonoGenericContext *context, MonoGenericSharingContext *gsctx, gboolean all_vt)
+{
+       MonoGenericInst *inst;
+       int i;
+
+       memset (gsctx, 0, sizeof (MonoGenericSharingContext));
+
+       if (context->class_inst) {
+               inst = context->class_inst;
+               gsctx->var_is_vt = g_new0 (gboolean, inst->type_argc);
+
+               for (i = 0; i < inst->type_argc; ++i) {
+                       MonoType *type = inst->type_argv [i];
+
+                       if (!all_vt && (MONO_TYPE_IS_REFERENCE (type) || (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR))) {
+                       } else {
+                               gsctx->var_is_vt [i] = TRUE;
+                       }
+               }
+       }
+       if (context->method_inst) {
+               inst = context->method_inst;
+               gsctx->mvar_is_vt = g_new0 (gboolean, inst->type_argc);
+
+               for (i = 0; i < inst->type_argc; ++i) {
+                       MonoType *type = inst->type_argv [i];
+
+                       if (!all_vt && (MONO_TYPE_IS_REFERENCE (type) || (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR))) {
+                       } else {
+                               gsctx->mvar_is_vt [i] = TRUE;
+                       }
+               }
+       }
+}
+
+void
+mini_init_gsctx (MonoGenericContext *context, MonoGenericSharingContext *gsctx)
+{
+       mini_init_gsctx_full (context, gsctx, FALSE);
+}
+
 #ifndef DISABLE_JIT
 /*
  * mini_method_compile:
@@ -4179,11 +4486,12 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        gboolean deadce_has_run = FALSE;
        gboolean try_generic_shared, try_llvm = FALSE;
        MonoMethod *method_to_compile, *method_to_register;
+       gboolean method_is_gshared = FALSE;
 
        InterlockedIncrement (&mono_jit_stats.methods_compiled);
        if (mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION)
                mono_profiler_method_jit (method);
-       if (MONO_PROBE_METHOD_COMPILE_BEGIN_ENABLED ())
+       if (MONO_METHOD_COMPILE_BEGIN_ENABLED ())
                MONO_PROBE_METHOD_COMPILE_BEGIN (method);
 
        if (compile_aot)
@@ -4193,10 +4501,10 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
                 * FIXME: Remove the method->klass->generic_class limitation.
                 */
                try_generic_shared = mono_class_generic_sharing_enabled (method->klass) &&
-                       (opts & MONO_OPT_GSHARED) && ((method->is_generic || method->klass->generic_container) || (!method->klass->generic_class && mono_method_is_generic_sharable_impl (method, TRUE)));
+                       (opts & MONO_OPT_GSHARED) && ((method->is_generic || method->klass->generic_container) || (!method->klass->generic_class && mono_method_is_generic_sharable_impl_full (method, TRUE, FALSE, FALSE)));
        else
                try_generic_shared = mono_class_generic_sharing_enabled (method->klass) &&
-                       (opts & MONO_OPT_GSHARED) && mono_method_is_generic_sharable_impl (method, FALSE);
+                       (opts & MONO_OPT_GSHARED) && mono_method_is_generic_sharable_impl_full (method, FALSE, FALSE, TRUE);
 
        if (opts & MONO_OPT_GSHARED) {
                if (try_generic_shared)
@@ -4205,16 +4513,34 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
                        mono_stats.generics_unsharable_methods++;
        }
 
+       if (mini_is_gsharedvt_sharable_method (method)) {
+               if (!mono_debug_count ())
+                       try_generic_shared = FALSE;
+               if (compile_aot)
+                       try_generic_shared = FALSE;
+       }
+
+       if (is_gsharedvt_method (method)) {
+               /* We are AOTing a gshared method directly */
+               method_is_gshared = TRUE;
+               g_assert (compile_aot);
+               try_generic_shared = TRUE;
+       }
+
 #ifdef ENABLE_LLVM
        try_llvm = mono_use_llvm;
 #endif
 
  restart_compile:
-       if (try_generic_shared) {
-               method_to_compile = mini_get_shared_method (method);
-               g_assert (method_to_compile);
-       } else {
+       if (method_is_gshared) {
                method_to_compile = method;
+       } else {
+               if (try_generic_shared) {
+                       method_to_compile = mini_get_shared_method (method);
+                       g_assert (method_to_compile);
+               } else {
+                       method_to_compile = method;
+               }
        }
 
        cfg = g_new0 (MonoCompile, 1);
@@ -4233,18 +4559,40 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        cfg->explicit_null_checks = debug_options.explicit_null_checks;
        cfg->soft_breakpoints = debug_options.soft_breakpoints;
        if (try_generic_shared)
-               cfg->generic_sharing_context = (MonoGenericSharingContext*)&cfg->generic_sharing_context;
+               cfg->generic_sharing_context = (MonoGenericSharingContext*)&cfg->gsctx;
        cfg->compile_llvm = try_llvm;
        cfg->token_info_hash = g_hash_table_new (NULL, NULL);
 
        if (cfg->gen_seq_points)
                cfg->seq_points = g_ptr_array_new ();
 
-       if (cfg->compile_aot && !try_generic_shared && (method->is_generic || method->klass->generic_container)) {
+       if (cfg->compile_aot && !try_generic_shared && (method->is_generic || method->klass->generic_container || method_is_gshared)) {
                cfg->exception_type = MONO_EXCEPTION_GENERIC_SHARING_FAILED;
                return cfg;
        }
 
+       if (cfg->generic_sharing_context && (mini_is_gsharedvt_sharable_method (method) || method_is_gshared)) {
+               MonoMethodInflated *inflated;
+               MonoGenericContext *context;
+
+               g_assert (method->is_inflated);
+               inflated = (MonoMethodInflated*)method;
+               context = &inflated->context;
+
+               // FIXME: Free the contents of gsctx if compilation fails
+               if (method_is_gshared) {
+                       /* We are compiling a gsharedvt method directly */
+                       g_assert (compile_aot);
+                       mini_init_gsctx_full (context, &cfg->gsctx, TRUE);
+               } else {
+                       mini_init_gsctx (context, &cfg->gsctx);
+               }
+
+               cfg->gsharedvt = TRUE;
+               // FIXME:
+               cfg->disable_llvm = TRUE;
+       }
+
        if (cfg->generic_sharing_context) {
                method_to_register = method_to_compile;
        } else {
@@ -4259,7 +4607,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
                cfg->exception_type = MONO_EXCEPTION_TYPE_LOAD;
                cfg->exception_message = g_strdup (mono_error_get_message (&err));
                mono_error_cleanup (&err);
-               if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
+               if (MONO_METHOD_COMPILE_END_ENABLED ())
                        MONO_PROBE_METHOD_COMPILE_END (method, FALSE);
                return cfg;
        }
@@ -4274,7 +4622,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
                        cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
                        cfg->exception_message = g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name);
                }
-               if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
+               if (MONO_METHOD_COMPILE_END_ENABLED ())
                        MONO_PROBE_METHOD_COMPILE_END (method, FALSE);
                return cfg;
        }
@@ -4321,7 +4669,8 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
 
                /* Temporarily disable this when running in the debugger until we have support
                 * for this in the debugger. */
-               cfg->disable_omit_fp = TRUE;
+               /* This is no longer needed with sdb */
+               //cfg->disable_omit_fp = TRUE;
 
                /* The debugger needs all locals to be on the stack or in a global register */
                cfg->disable_vreg_to_lvreg = TRUE;
@@ -4335,7 +4684,8 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
                cfg->opt &= ~MONO_OPT_INLINE;
                cfg->opt &= ~MONO_OPT_COPYPROP;
                cfg->opt &= ~MONO_OPT_CONSPROP;
-               cfg->opt &= ~MONO_OPT_GSHARED;
+               /* This is no longer needed with sdb */
+               //cfg->opt &= ~MONO_OPT_GSHARED;
 
                /* This is needed for the soft debugger, which doesn't like code after the epilog */
                cfg->disable_out_of_line_bblocks = TRUE;
@@ -4382,12 +4732,19 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
 
        if (cfg->verbose_level > 0) {
                char *method_name;
+
+               method_name = mono_method_full_name (method, TRUE);
+               g_print ("converting %s%s%smethod %s\n", COMPILE_LLVM (cfg) ? "llvm " : "", cfg->gsharedvt ? "gsharedvt " : "", (cfg->generic_sharing_context && !cfg->gsharedvt) ? "gshared " : "", method_name);
+               /*
                if (COMPILE_LLVM (cfg))
                        g_print ("converting llvm method %s\n", method_name = mono_method_full_name (method, TRUE));
+               else if (cfg->gsharedvt)
+                       g_print ("converting gsharedvt method %s\n", method_name = mono_method_full_name (method_to_compile, TRUE));
                else if (cfg->generic_sharing_context)
                        g_print ("converting shared method %s\n", method_name = mono_method_full_name (method_to_compile, TRUE));
                else
                        g_print ("converting method %s\n", method_name = mono_method_full_name (method, TRUE));
+               */
                g_free (method_name);
        }
 
@@ -4476,7 +4833,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        if (i < 0) {
                if (try_generic_shared && cfg->exception_type == MONO_EXCEPTION_GENERIC_SHARING_FAILED) {
                        if (compile_aot) {
-                               if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
+                               if (MONO_METHOD_COMPILE_END_ENABLED ())
                                        MONO_PROBE_METHOD_COMPILE_END (method, FALSE);
                                return cfg;
                        }
@@ -4486,7 +4843,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
                }
                g_assert (cfg->exception_type != MONO_EXCEPTION_GENERIC_SHARING_FAILED);
 
-               if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
+               if (MONO_METHOD_COMPILE_END_ENABLED ())
                        MONO_PROBE_METHOD_COMPILE_END (method, FALSE);
                /* cfg contains the details of the failure, so let the caller cleanup */
                return cfg;
@@ -4609,7 +4966,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
 
        /* after method_to_ir */
        if (parts == 1) {
-               if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
+               if (MONO_METHOD_COMPILE_END_ENABLED ())
                        MONO_PROBE_METHOD_COMPILE_END (method, TRUE);
                return cfg;
        }
@@ -4646,7 +5003,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
 
        /* after SSA translation */
        if (parts == 2) {
-               if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
+               if (MONO_METHOD_COMPILE_END_ENABLED ())
                        MONO_PROBE_METHOD_COMPILE_END (method, TRUE);
                return cfg;
        }
@@ -4713,7 +5070,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
 
        /* after SSA removal */
        if (parts == 3) {
-               if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
+               if (MONO_METHOD_COMPILE_END_ENABLED ())
                        MONO_PROBE_METHOD_COMPILE_END (method, TRUE);
                return cfg;
        }
@@ -4934,9 +5291,16 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
                mono_domain_unlock (cfg->domain);
        }
 
+#if 0
+       if (cfg->gsharedvt)
+               printf ("GSHAREDVT: %s\n", mono_method_full_name (cfg->method, TRUE));
+#endif
+
        /* collect statistics */
+#ifndef DISABLE_PERFCOUNTERS
        mono_perfcounters->jit_methods++;
        mono_perfcounters->jit_bytes += header->code_size;
+#endif
        mono_jit_stats.allocated_code_size += cfg->code_len;
        code_size_ratio = cfg->code_len;
        if (code_size_ratio > mono_jit_stats.biggest_method_size && mono_jit_stats.enabled) {
@@ -4952,7 +5316,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        }
        mono_jit_stats.native_code_size += cfg->code_len;
 
-       if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
+       if (MONO_METHOD_COMPILE_END_ENABLED ())
                MONO_PROBE_METHOD_COMPILE_END (method, TRUE);
 
        return cfg;
@@ -5005,7 +5369,7 @@ lookup_method_inner (MonoDomain *domain, MonoMethod *method)
        if (ji)
                return ji;
 
-       if (!mono_method_is_generic_sharable_impl (method, FALSE))
+       if (!mono_method_is_generic_sharable_impl_full (method, FALSE, FALSE, TRUE))
                return NULL;
        return mono_domain_lookup_shared_generic (domain, method);
 }
@@ -5141,7 +5505,7 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
                                return mono_get_addr_from_ftnptr ((gpointer)mono_icall_get_wrapper_full (mi, TRUE));
                        } else if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
-                               return mono_create_delegate_trampoline (method->klass);
+                               return mono_create_delegate_trampoline (target_domain, method->klass);
 #else
                                nm = mono_marshal_get_delegate_invoke (method, NULL);
                                return mono_get_addr_from_ftnptr (mono_compile_method (nm));
@@ -5163,9 +5527,42 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
                return NULL;
        }
 
+       if (method->wrapper_type == MONO_WRAPPER_UNKNOWN) {
+               WrapperInfo *info = mono_marshal_get_wrapper_info (method);
+
+               if (info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN || info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_OUT) {
+                       static MonoTrampInfo *in_tinfo, *out_tinfo;
+                       MonoTrampInfo *tinfo;
+                       MonoJitInfo *jinfo;
+                       gboolean is_in = info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN;
+
+                       if (is_in && in_tinfo)
+                               return in_tinfo->code;
+                       else if (!is_in && out_tinfo)
+                               return out_tinfo->code;
+
+                       /*
+                        * This is a special wrapper whose body is implemented in assembly, like a trampoline. We use a wrapper so EH
+                        * works.
+                        * FIXME: The caller signature doesn't match the callee, which might cause problems on some platforms
+                        */
+                       if (mono_aot_only)
+                               mono_aot_get_trampoline_full (is_in ? "gsharedvt_trampoline" : "gsharedvt_out_trampoline", &tinfo);
+                       else
+                               mono_arch_get_gsharedvt_trampoline (&tinfo, FALSE);
+                       jinfo = create_jit_info_for_trampoline (method, tinfo);
+                       mono_jit_info_table_add (mono_get_root_domain (), jinfo);
+                       if (is_in)
+                               in_tinfo = tinfo;
+                       else
+                               out_tinfo = tinfo;
+                       return tinfo->code;
+               }
+       }
+
        if (mono_aot_only) {
                char *fullname = mono_method_full_name (method, TRUE);
-               char *msg = g_strdup_printf ("Attempting to JIT compile method '%s' while running with --aot-only.\n", fullname);
+               char *msg = g_strdup_printf ("Attempting to JIT compile method '%s' while running with --aot-only. See http://docs.xamarin.com/ios/about/limitations for more information.\n", fullname);
 
                *jit_ex = mono_get_exception_execution_engine (msg);
                g_free (fullname);
@@ -5287,8 +5684,10 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
                mono_domain_jit_code_hash_unlock (target_domain);
                code = cfg->native_code;
 
-               if (cfg->generic_sharing_context && mono_method_is_generic_sharable_impl (method, FALSE))
+               if (cfg->generic_sharing_context && mono_method_is_generic_sharable_impl_full (method, FALSE, FALSE, TRUE))
                        mono_stats.generics_shared_methods++;
+               if (cfg->gsharedvt)
+                       mono_stats.gsharedvt_methods++;
        } else {
                mono_domain_jit_code_hash_unlock (target_domain);
        }
@@ -5403,6 +5802,14 @@ mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, MonoException
        else 
                target_domain = domain;
 
+       if (method->wrapper_type == MONO_WRAPPER_UNKNOWN) {
+               WrapperInfo *info = mono_marshal_get_wrapper_info (method);
+
+               g_assert (info);
+               if (info->subtype == WRAPPER_SUBTYPE_SYNCHRONIZED_INNER)
+                       method = info->d.synchronized_inner.method;
+       }
+
        info = lookup_method (target_domain, method);
        if (info) {
                /* We can't use a domain specific method in another domain */
@@ -5464,7 +5871,7 @@ static void
 invalidated_delegate_trampoline (char *desc)
 {
        g_error ("Unmanaged code called delegate of type %s which was already garbage collected.\n"
-                "See http://www.go-mono.com/delegate.html for an explanation and ways to fix this.",
+                "See http://www.mono-project.com/Diagnostic:Delegate for an explanation and ways to fix this.",
                 desc);
 }
 #endif
@@ -5659,8 +6066,7 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec
                                }
                        }
 
-                       if (mono_method_needs_static_rgctx_invoke (method, FALSE))
-                               info->compiled_method = mono_create_static_rgctx_trampoline (method, info->compiled_method);
+                       info->compiled_method = mini_add_method_trampoline (NULL, method, info->compiled_method, NULL, mono_method_needs_static_rgctx_invoke (method, FALSE));
                }
 
                /*
@@ -6239,7 +6645,7 @@ mini_init (const char *filename, const char *runtime_version)
        MonoRuntimeCallbacks callbacks;
        MonoThreadInfoRuntimeCallbacks ticallbacks;
 
-       MONO_PROBE_VES_INIT_BEGIN ();
+       MONO_VES_INIT_BEGIN ();
 
 #if defined(__linux__) && !defined(__native_client__)
        if (access ("/proc/self/maps", F_OK) != 0) {
@@ -6252,6 +6658,11 @@ mini_init (const char *filename, const char *runtime_version)
        if (!default_opt_set)
                default_opt = mono_parse_default_optimizations (NULL);
 
+#ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
+       if (mono_aot_only)
+               mono_set_generic_sharing_vt_supported (TRUE);
+#endif
+
        InitializeCriticalSection (&jit_mutex);
 
 #ifdef MONO_DEBUGGER_SUPPORTED
@@ -6340,7 +6751,6 @@ mini_init (const char *filename, const char *runtime_version)
                g_thread_init (NULL);
 
        mono_native_tls_alloc (&mono_jit_tls_id, NULL);
-       setup_jit_tls_data ((gpointer)-1, mono_thread_abort);
 
        if (default_opt & MONO_OPT_AOT)
                mono_aot_init ();
@@ -6397,6 +6807,7 @@ mini_init (const char *filename, const char *runtime_version)
        if (mono_aot_only) {
                /* This helps catch code allocation requests */
                mono_code_manager_set_read_only (domain->code_mp);
+               mono_marshal_use_aot_wrappers (TRUE);
        }
 
 #ifdef MONO_ARCH_HAVE_IMT
@@ -6407,6 +6818,9 @@ mini_init (const char *filename, const char *runtime_version)
                        mono_install_imt_thunk_builder (mono_arch_build_imt_thunk);
        }
 #endif
+       /*Init arch tls information only after the metadata side is inited to make sure we see dynamic appdomain tls keys*/
+       mono_arch_finish_init ();
+       
 
        /* This must come after mono_init () in the aot-only case */
        mono_exceptions_init ();
@@ -6429,6 +6843,11 @@ mini_init (const char *filename, const char *runtime_version)
        mono_add_internal_call ("Mono.Runtime::mono_runtime_install_handlers", 
                                mono_runtime_install_handlers);
 
+#ifdef PLATFORM_ANDROID
+       mono_add_internal_call ("System.Diagnostics.Debugger::Mono_UnhandledException_internal",
+                               mono_debugger_agent_unhandled_exception);
+#endif
+
        mono_create_helper_signatures ();
 
        register_jit_stats ();
@@ -6444,7 +6863,8 @@ mini_init (const char *filename, const char *runtime_version)
        register_icall (mono_trace_enter_method, "mono_trace_enter_method", NULL, TRUE);
        register_icall (mono_trace_leave_method, "mono_trace_leave_method", NULL, TRUE);
        register_icall (mono_get_lmf_addr, "mono_get_lmf_addr", "ptr", TRUE);
-       register_icall (mono_jit_thread_attach, "mono_jit_thread_attach", "void", TRUE);
+       register_icall (mono_jit_thread_attach, "mono_jit_thread_attach", "ptr ptr", TRUE);
+       register_icall (mono_jit_set_domain, "mono_jit_set_domain", "void ptr", TRUE);
        register_icall (mono_domain_get, "mono_domain_get", "ptr", TRUE);
 
        register_icall (mono_get_throw_exception (), "mono_arch_throw_exception", "void object", TRUE);
@@ -6610,6 +7030,7 @@ mini_init (const char *filename, const char *runtime_version)
        register_icall (mono_array_new_3, "mono_array_new_3", "object ptr int int int", FALSE);
        register_icall (mono_get_native_calli_wrapper, "mono_get_native_calli_wrapper", "ptr ptr ptr ptr", FALSE);
        register_icall (mono_resume_unwind, "mono_resume_unwind", "void", TRUE);
+       register_icall (mono_object_tostring_gsharedvt, "mono_object_tostring_gsharedvt", "object ptr ptr ptr", TRUE);
 
        register_icall (mono_gc_wbarrier_value_copy_bitmap, "mono_gc_wbarrier_value_copy_bitmap", "void ptr ptr int int", FALSE);
 
@@ -6646,7 +7067,7 @@ mini_init (const char *filename, const char *runtime_version)
 
        mono_profiler_runtime_initialized ();
 
-       MONO_PROBE_VES_INIT_END ();
+       MONO_VES_INIT_END ();
        
        return domain;
 }
@@ -6680,6 +7101,7 @@ print_jit_stats (void)
                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 ("Shared vtype generic methods: %ld\n", mono_stats.gsharedvt_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);
@@ -6699,10 +7121,6 @@ print_jit_stats (void)
                g_print ("JIT info table lookups: %ld\n", mono_stats.jit_info_table_lookup_count);
 
                g_print ("Hazardous pointers:     %ld\n", mono_stats.hazardous_pointer_count);
-               g_print ("Minor GC collections:   %ld\n", mono_stats.minor_gc_count);
-               g_print ("Major GC collections:   %ld\n", mono_stats.major_gc_count);
-               g_print ("Minor GC time in msecs: %lf\n", (double)mono_stats.minor_gc_time_usecs / 1000.0);
-               g_print ("Major GC time in msecs: %lf\n", (double)mono_stats.major_gc_time_usecs / 1000.0);
                if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
                        g_print ("\nDecl security check   : %ld\n", mono_jit_stats.cas_declsec_check);
                        g_print ("LinkDemand (user)     : %ld\n", mono_jit_stats.cas_linkdemand);
@@ -6800,8 +7218,7 @@ void
 mono_set_defaults (int verbose_level, guint32 opts)
 {
        mini_verbose = verbose_level;
-       default_opt = opts;
-       default_opt_set = TRUE;
+       mono_set_optimizations (opts);
 }
 
 void
@@ -6815,6 +7232,9 @@ mono_set_optimizations (guint32 opts)
 {
        default_opt = opts;
        default_opt_set = TRUE;
+#ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
+       mono_set_generic_sharing_vt_supported (mono_aot_only || ((default_opt & MONO_OPT_GSHAREDVT) != 0));
+#endif
 }
 
 void
@@ -6823,11 +7243,12 @@ mono_set_verbose_level (guint32 level)
        mini_verbose = level;
 }
 
-/*
+/**
  * mono_get_runtime_build_info:
  *
- *   Return the runtime version + build date in string format.
- * The returned string is owned by the caller.
+ * Return the runtime version + build date in string format.
+ * The returned string is owned by the caller. The returned string
+ * format is "VERSION (FULL_VERSION BUILD_DATE)" and build date is optional.
  */
 char*
 mono_get_runtime_build_info (void)
@@ -6918,3 +7339,71 @@ mono_cfg_set_exception (MonoCompile *cfg, int type)
 }
 
 #endif
+
+/* Dummy versions of some arch specific functions to avoid ifdefs at call sites */
+
+#ifndef MONO_ARCH_GSHAREDVT_SUPPORTED
+
+gboolean
+mono_arch_gsharedvt_sig_supported (MonoMethodSignature *sig)
+{
+       return FALSE;
+}
+
+gpointer
+mono_arch_get_gsharedvt_call_info (gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, MonoGenericSharingContext *gsctx, gboolean gsharedvt_in, gint32 vcall_offset, gboolean calli)
+{
+       g_assert_not_reached ();
+       return NULL;
+}
+
+gpointer
+mono_arch_get_gsharedvt_arg_trampoline (MonoDomain *domain, gpointer arg, gpointer addr)
+{
+       g_assert_not_reached ();
+       return NULL;
+}
+
+gpointer
+mono_arch_get_gsharedvt_trampoline (MonoTrampInfo **info, gboolean aot)
+{
+       g_assert_not_reached ();
+       return NULL;
+}
+
+#endif
+
+#ifdef DISABLE_JIT
+
+gpointer
+mono_arch_get_gsharedvt_arg_trampoline (MonoDomain *domain, gpointer arg, gpointer addr)
+{
+       g_assert_not_reached ();
+       return NULL;
+}
+
+gpointer
+mono_arch_get_gsharedvt_trampoline (MonoTrampInfo **info, gboolean aot)
+{
+       g_assert_not_reached ();
+       return NULL;
+}
+
+#endif
+
+#if defined(MONO_ARCH_GSHAREDVT_SUPPORTED) && !defined(MONOTOUCH) && !defined(MONO_EXTENSIONS)
+
+gboolean
+mono_arch_gsharedvt_sig_supported (MonoMethodSignature *sig)
+{
+       return FALSE;
+}
+
+gpointer
+mono_arch_get_gsharedvt_call_info (gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, MonoGenericSharingContext *gsctx, gboolean gsharedvt_in, gint32 vcall_offset, gboolean calli)
+{
+       NOT_IMPLEMENTED;
+       return NULL;
+}
+
+#endif