Merge pull request #505 from roji/shutdown_flow
[mono.git] / mono / mini / mini.c
index 5f035d7e4ef6b39d36069617e995d97219ad9a62..28b66be959ff9fe33df01979916b3dd65ec2cc44 100644 (file)
@@ -367,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) {
@@ -388,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);
@@ -862,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);
        }
@@ -928,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);
        }
@@ -944,26 +952,28 @@ 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);
 }
 
+#ifndef DISABLE_JIT
+
 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);
 }
@@ -1098,6 +1108,8 @@ mono_decompose_op_imm (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins)
        bb->max_vreg = MAX (bb->max_vreg, cfg->next_vreg);
 }
 
+#endif
+
 static void
 set_vreg_to_inst (MonoCompile *cfg, int vreg, MonoInst *inst)
 {
@@ -1153,6 +1165,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);
@@ -1746,18 +1761,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;
                }
 
@@ -1765,7 +1784,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)) {
@@ -2039,17 +2057,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;
                }
 
@@ -2057,7 +2082,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 {
@@ -2110,9 +2134,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;
                        }
                }
 
@@ -2264,8 +2292,8 @@ mono_find_jit_opcode_emulation (int opcode)
        return NULL;
 }
 
-void
-mono_register_opcode_emulation (int opcode, const char *name, const char *sigstr, gpointer func, gboolean no_throw)
+static void
+register_opcode_emulation (int opcode, const char *name, const char *sigstr, gpointer func, const char *symbol, gboolean no_throw)
 {
        MonoJitICallInfo *info;
        MonoMethodSignature *sig = mono_create_icall_signature (sigstr);
@@ -2273,7 +2301,7 @@ mono_register_opcode_emulation (int opcode, const char *name, const char *sigstr
        g_assert (!sig->hasthis);
        g_assert (sig->param_count < 3);
 
-       info = mono_register_jit_icall (func, name, sig, no_throw);
+       info = mono_register_jit_icall_full (func, name, sig, no_throw, symbol);
 
        if (emul_opcode_num >= emul_opcode_alloced) {
                int incr = emul_opcode_alloced? emul_opcode_alloced/2: 16;
@@ -2287,11 +2315,28 @@ mono_register_opcode_emulation (int opcode, const char *name, const char *sigstr
        emul_opcode_hit_cache [opcode >> (EMUL_HIT_SHIFT + 3)] |= (1 << (opcode & EMUL_HIT_MASK));
 }
 
+/*
+ * For JIT icalls implemented in C.
+ * NAME should be the same as the name of the C function whose address is FUNC.
+ */
 static void
 register_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
 {
        MonoMethodSignature *sig;
 
+       if (sigstr)
+               sig = mono_create_icall_signature (sigstr);
+       else
+               sig = NULL;
+
+       mono_register_jit_icall_full (func, name, sig, save, save ? name : NULL);
+}
+
+static void
+register_dyn_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
+{
+       MonoMethodSignature *sig;
+
        if (sigstr)
                sig = mono_create_icall_signature (sigstr);
        else
@@ -2554,7 +2599,8 @@ mono_get_lmf_addr (void)
 #else
        MonoJitTlsData *jit_tls;
 
-       if ((jit_tls = mono_native_tls_get_value (mono_jit_tls_id)))
+       jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
+       if (G_LIKELY (jit_tls))
                return &jit_tls->lmf;
 
        /*
@@ -2898,6 +2944,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;
        }
@@ -2934,6 +2984,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);
        }
@@ -2970,13 +3022,18 @@ mono_patch_info_equal (gconstpointer ka, gconstpointer kb)
                break;
        case MONO_PATCH_INFO_INTERNAL_METHOD:
                return g_str_equal (ji1->data.name, ji2->data.name);
-
        case MONO_PATCH_INFO_RGCTX_FETCH: {
                MonoJumpInfoRgctxEntry *e1 = ji1->data.rgctx_entry;
                MonoJumpInfoRgctxEntry *e2 = ji2->data.rgctx_entry;
 
                return e1->method == e2->method && e1->in_mrgctx == e2->in_mrgctx && e1->info_type == e2->info_type && mono_patch_info_equal (e1->data, e2->data);
        }
+       case MONO_PATCH_INFO_GSHAREDVT_CALL: {
+               MonoJumpInfoGSharedVtCall *c1 = ji1->data.gsharedvt;
+               MonoJumpInfoGSharedVtCall *c2 = ji2->data.gsharedvt;
+
+               return c1->sig == c2->sig && c1->method == c2->method;
+       }
        default:
                if (ji1->data.target != ji2->data.target)
                        return 0;
@@ -3028,6 +3085,15 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
                target = mono_icall_get_wrapper (mi);
                break;
        }
+       case MONO_PATCH_INFO_JIT_ICALL_ADDR: {
+               MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name);
+               if (!mi) {
+                       g_warning ("unknown MONO_PATCH_INFO_JIT_ICALL_ADDR %s", patch_info->data.name);
+                       g_assert_not_reached ();
+               }
+               target = mi->func;
+               break;
+       }
        case MONO_PATCH_INFO_METHOD_JUMP:
                target = mono_create_jump_trampoline (domain, patch_info->data.method, FALSE);
 #if defined(__native_client__) && defined(__native_client_codegen__)
@@ -3211,15 +3277,6 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
                                g_error ("Unregistered icall '%s'\n", mono_method_full_name (patch_info->data.method, TRUE));
                }
                break;
-       case MONO_PATCH_INFO_JIT_ICALL_ADDR: {
-               MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name);
-               if (!mi) {
-                       g_warning ("unknown MONO_PATCH_INFO_JIT_ICALL_ADDR %s", patch_info->data.name);
-                       g_assert_not_reached ();
-               }
-               target = mi->func;
-               break;
-       }
        case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG:
                target = mono_thread_interruption_request_flag ();
                break;
@@ -3250,6 +3307,16 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
                case MONO_PATCH_INFO_FIELD:
                        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;
@@ -3295,6 +3362,10 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
                target = mono_domain_alloc0 (domain, sizeof (gpointer));
                break;
        }
+       case MONO_PATCH_INFO_JIT_TLS_ID: {
+               target = (gpointer)mono_jit_tls_id;
+               break;
+       }
        default:
                g_assert_not_reached ();
        }
@@ -3393,8 +3464,6 @@ mono_compile_create_vars (MonoCompile *cfg)
        mono_arch_create_vars (cfg);
 }
 
-#endif /* #ifndef DISABLE_JIT */
-
 void
 mono_print_code (MonoCompile *cfg, const char* msg)
 {
@@ -3404,8 +3473,6 @@ mono_print_code (MonoCompile *cfg, const char* msg)
                mono_print_bb (bb, msg);
 }
 
-#ifndef DISABLE_JIT
-
 static void
 mono_postprocess_patches (MonoCompile *cfg)
 {
@@ -3423,27 +3490,14 @@ mono_postprocess_patches (MonoCompile *cfg)
                         */
                        if (info) {
                                //printf ("TEST %s %p\n", info->name, patch_info->data.target);
-                               // FIXME: CLEAN UP THIS MESS.
-                               if ((cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) && 
-                                       strstr (cfg->method->name, info->name)) {
-                                       /*
-                                        * This is an icall wrapper, and this is a call to the
-                                        * wrapped function.
-                                        */
-                                       if (cfg->compile_aot) {
-                                               patch_info->type = MONO_PATCH_INFO_JIT_ICALL_ADDR;
-                                               patch_info->data.name = info->name;
-                                       }
-                               } else {
-                                       /* for these array methods we currently register the same function pointer
-                                        * since it's a vararg function. But this means that mono_find_jit_icall_by_addr ()
-                                        * will return the incorrect one depending on the order they are registered.
-                                        * See tests/test-arr.cs
-                                        */
-                                       if (strstr (info->name, "ves_array_new_va_") == NULL && strstr (info->name, "ves_array_element_address_") == NULL) {
-                                               patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
-                                               patch_info->data.name = info->name;
-                                       }
+                               /* for these array methods we currently register the same function pointer
+                                * since it's a vararg function. But this means that mono_find_jit_icall_by_addr ()
+                                * will return the incorrect one depending on the order they are registered.
+                                * See tests/test-arr.cs
+                                */
+                               if (strstr (info->name, "ves_array_new_va_") == NULL && strstr (info->name, "ves_array_element_address_") == NULL) {
+                                       patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
+                                       patch_info->data.name = info->name;
                                }
                        }
 
@@ -3895,6 +3949,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)
 {
@@ -3985,7 +4067,11 @@ create_jit_info (MonoCompile *cfg, MonoMethod *method_to_compile)
                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 ||
@@ -4206,67 +4292,165 @@ 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;
+}
+
+static gboolean
+has_ref_constraint (MonoGenericParamInfo *info)
+{
+       MonoClass **constraints;
+
+       //return FALSE;
+
+       if (info && info->constraints) {
+               constraints = info->constraints;
+
+               while (*constraints) {
+                       MonoClass *cklass = *constraints;
+                       if (!(cklass == mono_defaults.object_class || (cklass->image == mono_defaults.corlib && !strcmp (cklass->name, "ValueType")) || MONO_CLASS_IS_INTERFACE (cklass)))
+                               return TRUE;
+                       constraints ++;
+               }
+       }
+       return FALSE;
+}
+
+static MonoGenericInst*
+get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt)
+{
+       MonoGenericInst *res;
+       MonoType **type_argv;
+       int i;
+
+       type_argv = g_new0 (MonoType*, inst->type_argc);
+       for (i = 0; i < inst->type_argc; ++i) {
+               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_inst->type_argv [i];
+               } else if (all_vt) {
+                       if (container && has_ref_constraint (&container->type_params [i].info))
+                               type_argv [i] = shared_inst->type_argv [i];
+                       else
+                               type_argv [i] = get_gsharedvt_type (shared_inst->type_argv [i]);
+               } else if (gsharedvt) {
+                       type_argv [i] = get_gsharedvt_type (shared_inst->type_argv [i]);
+               } else {
+                       type_argv [i] = inst->type_argv [i];
+               }
+       }
+
+       res = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
+       g_free (type_argv);
+       return res;
+}
+
 /*
- * 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.
+ * METHOD can be a non-inflated generic method.
  */
 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;
+       MonoGenericContainer *class_container, *method_container = NULL;
 
-       if (method->is_generic || method->klass->generic_container)
+       if (method->is_generic || method->klass->generic_container) {
                declaring_method = method;
-       else
+       } else {
                declaring_method = mono_method_get_declaring_generic_method (method);
+       }
 
        if (declaring_method->is_generic)
                shared_context = mono_method_get_generic_container (declaring_method)->context;
        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);
+
+               class_container = declaring_method->klass->generic_container;
+               method_container = mono_method_get_generic_container (declaring_method);
 
                /* 
                 * Create the shared context by replacing the ref type arguments with
                 * type parameters, and keeping the rest.
                 */
                partial = TRUE;
-               inst = context->class_inst;
-               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)
-                                       type_argv [i] = shared_context.class_inst->type_argv [i];
-                               else
-                                       type_argv [i] = inst->type_argv [i];
-                       }
-
-                       shared_context.class_inst = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
-                       g_free (type_argv);
-               }
-
-               inst = context->method_inst;
-               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)
-                                       type_argv [i] = shared_context.method_inst->type_argv [i];
-                               else
-                                       type_argv [i] = inst->type_argv [i];
-                       }
+               if (context)
+                       inst = context->class_inst;
+               else
+                       inst = shared_context.class_inst;
+               if (inst)
+                       shared_context.class_inst = get_shared_inst (inst, shared_context.class_inst, class_container, all_vt, gsharedvt);
 
-                       shared_context.method_inst = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
-                       g_free (type_argv);
-               }
+               if (context)
+                       inst = context->method_inst;
+               else
+                       inst = shared_context.method_inst;
+               if (inst)
+                       shared_context.method_inst = get_shared_inst (inst, shared_context.method_inst, method_container, all_vt, gsharedvt);
        }
 
     res = mono_class_inflate_generic_method (declaring_method, &shared_context);
@@ -4277,6 +4461,44 @@ mini_get_shared_method (MonoMethod *method)
        return res;
 }
 
+MonoMethod*
+mini_get_shared_method (MonoMethod *method)
+{
+       return mini_get_shared_method_full (method, FALSE, FALSE);
+}
+
+void
+mini_init_gsctx (MonoGenericContext *context, MonoGenericSharingContext *gsctx)
+{
+       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 ((type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && type->data.generic_param->serial == 1)
+                               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 ((type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && type->data.generic_param->serial == 1)
+                               gsctx->mvar_is_vt [i] = TRUE;
+               }
+       }
+}
+
 #ifndef DISABLE_JIT
 /*
  * mini_method_compile:
@@ -4302,6 +4524,7 @@ 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)
@@ -4316,10 +4539,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)
@@ -4328,16 +4551,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);
@@ -4356,18 +4597,43 @@ 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;
+
+               // FIXME: Free the contents of gsctx if compilation fails
+               if (method_is_gshared) {
+                       g_assert (method->is_inflated);
+                       inflated = (MonoMethodInflated*)method;
+                       context = &inflated->context;
+
+                       /* We are compiling a gsharedvt method directly */
+                       g_assert (compile_aot);
+               } else {
+                       g_assert (method_to_compile->is_inflated);
+                       inflated = (MonoMethodInflated*)method_to_compile;
+                       context = &inflated->context;
+               }
+
+               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 {
@@ -4507,12 +4773,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);
        }
 
@@ -5059,9 +5332,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) {
@@ -5130,7 +5410,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);
 }
@@ -5288,9 +5568,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);
@@ -5412,8 +5725,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);
        }
@@ -5499,17 +5814,16 @@ mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, MonoException
        MonoJitInfo *info;
        gpointer code, p;
        MonoJitICallInfo *callinfo = NULL;
+       WrapperInfo *winfo = NULL;
 
        /*
         * ICALL wrappers are handled specially, since there is only one copy of them
         * shared by all appdomains.
         */
-       if ((method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) && (strstr (method->name, "__icall_wrapper_") == method->name)) {
-               const char *icall_name;
-
-               icall_name = method->name + strlen ("__icall_wrapper_");
-               g_assert (icall_name);
-               callinfo = mono_find_jit_icall_by_name (icall_name);
+       if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
+               winfo = mono_marshal_get_wrapper_info (method);
+       if (winfo && winfo->subtype == WRAPPER_SUBTYPE_ICALL_WRAPPER) {
+               callinfo = mono_find_jit_icall_by_addr (winfo->d.icall.func);
                g_assert (callinfo);
 
                /* Must be domain neutral since there is only one copy */
@@ -5597,7 +5911,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
@@ -5792,8 +6106,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, mono_method_needs_static_rgctx_invoke (method, FALSE));
                }
 
                /*
@@ -5817,7 +6130,7 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec
                                        supported = FALSE;
                        }
 
-                       if (method->klass->contextbound || !info->compiled_method)
+                       if (mono_class_is_contextbound (method->klass) || !info->compiled_method)
                                supported = FALSE;
 
                        if (supported)
@@ -6089,6 +6402,7 @@ SIG_HANDLER_SIGNATURE (mono_sigint_signal_handler)
        mono_arch_handle_exception (ctx, exc);
 }
 
+#ifndef DISABLE_REMOTING
 /* mono_jit_create_remoting_trampoline:
  * @method: pointer to the method info
  *
@@ -6109,14 +6423,16 @@ mono_jit_create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, Mon
        }
 
        if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) || 
-           (mono_method_signature (method)->hasthis && (method->klass->marshalbyref || method->klass == mono_defaults.object_class))) {
+           (mono_method_signature (method)->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))) {
                nm = mono_marshal_get_remoting_invoke_for_target (method, target);
                addr = mono_compile_method (nm);
-       } else {
+       } else
+       {
                addr = mono_compile_method (method);
        }
        return mono_get_addr_from_ftnptr (addr);
 }
+#endif
 
 static gpointer *vtable_trampolines;
 static int vtable_trampolines_size;
@@ -6357,9 +6673,10 @@ mini_free_jit_domain_info (MonoDomain *domain)
        g_hash_table_destroy (info->runtime_invoke_hash);
        g_hash_table_destroy (info->seq_points);
        g_hash_table_destroy (info->arch_seq_points);
-
        if (info->agent_info)
                mono_debugger_agent_free_domain_info (domain);
+       if (info->gsharedvt_arg_tramp_hash)
+               g_hash_table_destroy (info->gsharedvt_arg_tramp_hash);
 
        g_free (domain->runtime_info);
        domain->runtime_info = NULL;
@@ -6385,6 +6702,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
@@ -6473,7 +6795,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 ();
@@ -6505,7 +6826,9 @@ mini_init (const char *filename, const char *runtime_version)
        mono_install_free_method (mono_jit_free_method);
        mono_install_trampoline (mono_create_jit_trampoline);
        mono_install_jump_trampoline (mono_create_jump_trampoline);
+#ifndef DISABLE_REMOTING
        mono_install_remoting_trampoline (mono_jit_create_remoting_trampoline);
+#endif
        mono_install_delegate_trampoline (mono_create_delegate_trampoline);
        mono_install_create_domain_hook (mini_create_jit_domain_info);
        mono_install_free_domain_hook (mini_free_jit_domain_info);
@@ -6566,7 +6889,14 @@ 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
+
+#ifndef DISABLE_JIT
        mono_create_helper_signatures ();
+#endif
 
        register_jit_stats ();
 
@@ -6585,15 +6915,16 @@ mini_init (const char *filename, const char *runtime_version)
        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);
-       register_icall (mono_get_rethrow_exception (), "mono_arch_rethrow_exception", "void object", TRUE);
-       register_icall (mono_get_throw_corlib_exception (), "mono_arch_throw_corlib_exception", 
-                                "void ptr", TRUE);
+       register_dyn_icall (mono_get_throw_exception (), "mono_arch_throw_exception", "void object", TRUE);
+       register_dyn_icall (mono_get_rethrow_exception (), "mono_arch_rethrow_exception", "void object", TRUE);
+       register_dyn_icall (mono_get_throw_corlib_exception (), "mono_arch_throw_corlib_exception", "void ptr", TRUE);
        register_icall (mono_thread_get_undeniable_exception, "mono_thread_get_undeniable_exception", "object", FALSE);
        register_icall (mono_thread_interruption_checkpoint, "mono_thread_interruption_checkpoint", "void", FALSE);
        register_icall (mono_thread_force_interruption_checkpoint, "mono_thread_force_interruption_checkpoint", "void", FALSE);
+#ifndef DISABLE_REMOTING
        register_icall (mono_load_remote_field_new, "mono_load_remote_field_new", "object object ptr ptr", FALSE);
        register_icall (mono_store_remote_field_new, "mono_store_remote_field_new", "void object ptr ptr object", FALSE);
+#endif
 
 #if defined(__native_client__) || defined(__native_client_codegen__)
        register_icall (mono_nacl_gc, "mono_nacl_gc", "void", TRUE);
@@ -6604,102 +6935,102 @@ mini_init (const char *filename, const char *runtime_version)
         * rule to the burg files, because we need the arity information to be correct.
         */
 #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
-       mono_register_opcode_emulation (OP_LMUL, "__emul_lmul", "long long long", mono_llmult, TRUE);
-       mono_register_opcode_emulation (OP_LDIV, "__emul_ldiv", "long long long", mono_lldiv, FALSE);
-       mono_register_opcode_emulation (OP_LDIV_UN, "__emul_ldiv_un", "long long long", mono_lldiv_un, FALSE);
-       mono_register_opcode_emulation (OP_LREM, "__emul_lrem", "long long long", mono_llrem, FALSE);
-       mono_register_opcode_emulation (OP_LREM_UN, "__emul_lrem_un", "long long long", mono_llrem_un, FALSE);
-       mono_register_opcode_emulation (OP_LMUL_OVF_UN, "__emul_lmul_ovf_un", "long long long", mono_llmult_ovf_un, FALSE);
-       mono_register_opcode_emulation (OP_LMUL_OVF, "__emul_lmul_ovf", "long long long", mono_llmult_ovf, FALSE);
+       register_opcode_emulation (OP_LMUL, "__emul_lmul", "long long long", mono_llmult, "mono_llmult", TRUE);
+       register_opcode_emulation (OP_LDIV, "__emul_ldiv", "long long long", mono_lldiv, "mono_lldiv", FALSE);
+       register_opcode_emulation (OP_LDIV_UN, "__emul_ldiv_un", "long long long", mono_lldiv_un, "mono_lldiv_un", FALSE);
+       register_opcode_emulation (OP_LREM, "__emul_lrem", "long long long", mono_llrem, "mono_llrem", FALSE);
+       register_opcode_emulation (OP_LREM_UN, "__emul_lrem_un", "long long long", mono_llrem_un, "mono_llrem_un", FALSE);
+       register_opcode_emulation (OP_LMUL_OVF_UN, "__emul_lmul_ovf_un", "long long long", mono_llmult_ovf_un, "mono_llmult_ovf_un", FALSE);
+       register_opcode_emulation (OP_LMUL_OVF, "__emul_lmul_ovf", "long long long", mono_llmult_ovf, "mono_llmult_ovf", FALSE);
 #endif
 
 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
-       mono_register_opcode_emulation (OP_LSHL, "__emul_lshl", "long long int32", mono_lshl, TRUE);
-       mono_register_opcode_emulation (OP_LSHR, "__emul_lshr", "long long int32", mono_lshr, TRUE);
-       mono_register_opcode_emulation (OP_LSHR_UN, "__emul_lshr_un", "long long int32", mono_lshr_un, TRUE);
+       register_opcode_emulation (OP_LSHL, "__emul_lshl", "long long int32", mono_lshl, "mono_lshl", TRUE);
+       register_opcode_emulation (OP_LSHR, "__emul_lshr", "long long int32", mono_lshr, "mono_lshr", TRUE);
+       register_opcode_emulation (OP_LSHR_UN, "__emul_lshr_un", "long long int32", mono_lshr_un, "mono_lshr_un", TRUE);
 #endif
 
 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
-       mono_register_opcode_emulation (OP_IDIV, "__emul_op_idiv", "int32 int32 int32", mono_idiv, FALSE);
-       mono_register_opcode_emulation (OP_IDIV_UN, "__emul_op_idiv_un", "int32 int32 int32", mono_idiv_un, FALSE);
-       mono_register_opcode_emulation (OP_IREM, "__emul_op_irem", "int32 int32 int32", mono_irem, FALSE);
-       mono_register_opcode_emulation (OP_IREM_UN, "__emul_op_irem_un", "int32 int32 int32", mono_irem_un, FALSE);
+       register_opcode_emulation (OP_IDIV, "__emul_op_idiv", "int32 int32 int32", mono_idiv, "mono_idiv", FALSE);
+       register_opcode_emulation (OP_IDIV_UN, "__emul_op_idiv_un", "int32 int32 int32", mono_idiv_un, "mono_idiv_un", FALSE);
+       register_opcode_emulation (OP_IREM, "__emul_op_irem", "int32 int32 int32", mono_irem, "mono_irem", FALSE);
+       register_opcode_emulation (OP_IREM_UN, "__emul_op_irem_un", "int32 int32 int32", mono_irem_un, "mono_irem_un", FALSE);
 #endif
 
 #ifdef MONO_ARCH_EMULATE_MUL_DIV
-       mono_register_opcode_emulation (OP_IMUL, "__emul_op_imul", "int32 int32 int32", mono_imul, TRUE);
+       register_opcode_emulation (OP_IMUL, "__emul_op_imul", "int32 int32 int32", mono_imul, "mono_imul", TRUE);
 #endif
 
 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
-       mono_register_opcode_emulation (OP_IMUL_OVF, "__emul_op_imul_ovf", "int32 int32 int32", mono_imul_ovf, FALSE);
-       mono_register_opcode_emulation (OP_IMUL_OVF_UN, "__emul_op_imul_ovf_un", "int32 int32 int32", mono_imul_ovf_un, FALSE);
+       register_opcode_emulation (OP_IMUL_OVF, "__emul_op_imul_ovf", "int32 int32 int32", mono_imul_ovf, "mono_imul_ovf", FALSE);
+       register_opcode_emulation (OP_IMUL_OVF_UN, "__emul_op_imul_ovf_un", "int32 int32 int32", mono_imul_ovf_un, "mono_imul_ovf_un", FALSE);
 #endif
 
 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT)
-       mono_register_opcode_emulation (OP_FDIV, "__emul_fdiv", "double double double", mono_fdiv, FALSE);
+       register_opcode_emulation (OP_FDIV, "__emul_fdiv", "double double double", mono_fdiv, "mono_fdiv", FALSE);
 #endif
 
-       mono_register_opcode_emulation (OP_FCONV_TO_U8, "__emul_fconv_to_u8", "ulong double", mono_fconv_u8, FALSE);
-       mono_register_opcode_emulation (OP_FCONV_TO_U4, "__emul_fconv_to_u4", "uint32 double", mono_fconv_u4, FALSE);
-       mono_register_opcode_emulation (OP_FCONV_TO_OVF_I8, "__emul_fconv_to_ovf_i8", "long double", mono_fconv_ovf_i8, FALSE);
-       mono_register_opcode_emulation (OP_FCONV_TO_OVF_U8, "__emul_fconv_to_ovf_u8", "ulong double", mono_fconv_ovf_u8, FALSE);
+       register_opcode_emulation (OP_FCONV_TO_U8, "__emul_fconv_to_u8", "ulong double", mono_fconv_u8, "mono_fconv_u8", FALSE);
+       register_opcode_emulation (OP_FCONV_TO_U4, "__emul_fconv_to_u4", "uint32 double", mono_fconv_u4, "mono_fconv_u4", FALSE);
+       register_opcode_emulation (OP_FCONV_TO_OVF_I8, "__emul_fconv_to_ovf_i8", "long double", mono_fconv_ovf_i8, "mono_fconv_ovf_i8", FALSE);
+       register_opcode_emulation (OP_FCONV_TO_OVF_U8, "__emul_fconv_to_ovf_u8", "ulong double", mono_fconv_ovf_u8, "mono_fconv_ovf_u8", FALSE);
 
 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
-       mono_register_opcode_emulation (OP_FCONV_TO_I8, "__emul_fconv_to_i8", "long double", mono_fconv_i8, FALSE);
+       register_opcode_emulation (OP_FCONV_TO_I8, "__emul_fconv_to_i8", "long double", mono_fconv_i8, "mono_fconv_i8", FALSE);
 #endif
 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
-       mono_register_opcode_emulation (OP_ICONV_TO_R_UN, "__emul_iconv_to_r_un", "double int32", mono_conv_to_r8_un, FALSE);
+       register_opcode_emulation (OP_ICONV_TO_R_UN, "__emul_iconv_to_r_un", "double int32", mono_conv_to_r8_un, "mono_conv_to_r8_un", FALSE);
 #endif
 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
-       mono_register_opcode_emulation (OP_LCONV_TO_R8, "__emul_lconv_to_r8", "double long", mono_lconv_to_r8, FALSE);
+       register_opcode_emulation (OP_LCONV_TO_R8, "__emul_lconv_to_r8", "double long", mono_lconv_to_r8, "mono_lconv_to_r8", FALSE);
 #endif
 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
-       mono_register_opcode_emulation (OP_LCONV_TO_R4, "__emul_lconv_to_r4", "float long", mono_lconv_to_r4, FALSE);
+       register_opcode_emulation (OP_LCONV_TO_R4, "__emul_lconv_to_r4", "float long", mono_lconv_to_r4, "mono_lconv_to_r4", FALSE);
 #endif
 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
-       mono_register_opcode_emulation (OP_LCONV_TO_R_UN, "__emul_lconv_to_r8_un", "double long", mono_lconv_to_r8_un, FALSE);
+       register_opcode_emulation (OP_LCONV_TO_R_UN, "__emul_lconv_to_r8_un", "double long", mono_lconv_to_r8_un, "mono_lconv_to_r8_un", FALSE);
 #endif
 #ifdef MONO_ARCH_EMULATE_FREM
 #if defined(__default_codegen__)
-       mono_register_opcode_emulation (OP_FREM, "__emul_frem", "double double double", fmod, FALSE);
+       register_opcode_emulation (OP_FREM, "__emul_frem", "double double double", fmod, "fmod", FALSE);
 #elif defined(__native_client_codegen__)
-       mono_register_opcode_emulation (OP_FREM, "__emul_frem", "double double double", mono_fmod, FALSE);
+       register_opcode_emulation (OP_FREM, "__emul_frem", "double double double", mono_fmod, "mono_fmod", FALSE);
 #endif
 #endif
 
 #ifdef MONO_ARCH_SOFT_FLOAT
-       mono_register_opcode_emulation (OP_FSUB, "__emul_fsub", "double double double", mono_fsub, FALSE);
-       mono_register_opcode_emulation (OP_FADD, "__emul_fadd", "double double double", mono_fadd, FALSE);
-       mono_register_opcode_emulation (OP_FMUL, "__emul_fmul", "double double double", mono_fmul, FALSE);
-       mono_register_opcode_emulation (OP_FNEG, "__emul_fneg", "double double", mono_fneg, FALSE);
-       mono_register_opcode_emulation (OP_ICONV_TO_R8, "__emul_iconv_to_r8", "double int32", mono_conv_to_r8, FALSE);
-       mono_register_opcode_emulation (OP_ICONV_TO_R4, "__emul_iconv_to_r4", "double int32", mono_conv_to_r4, FALSE);
-       mono_register_opcode_emulation (OP_FCONV_TO_R4, "__emul_fconv_to_r4", "double double", mono_fconv_r4, FALSE);
-       mono_register_opcode_emulation (OP_FCONV_TO_I1, "__emul_fconv_to_i1", "int8 double", mono_fconv_i1, FALSE);
-       mono_register_opcode_emulation (OP_FCONV_TO_I2, "__emul_fconv_to_i2", "int16 double", mono_fconv_i2, FALSE);
-       mono_register_opcode_emulation (OP_FCONV_TO_I4, "__emul_fconv_to_i4", "int32 double", mono_fconv_i4, FALSE);
-       mono_register_opcode_emulation (OP_FCONV_TO_U1, "__emul_fconv_to_u1", "uint8 double", mono_fconv_u1, FALSE);
-       mono_register_opcode_emulation (OP_FCONV_TO_U2, "__emul_fconv_to_u2", "uint16 double", mono_fconv_u2, FALSE);
+       register_opcode_emulation (OP_FSUB, "__emul_fsub", "double double double", mono_fsub, "mono_fsub", FALSE);
+       register_opcode_emulation (OP_FADD, "__emul_fadd", "double double double", mono_fadd, "mono_fadd", FALSE);
+       register_opcode_emulation (OP_FMUL, "__emul_fmul", "double double double", mono_fmul, "mono_fmul", FALSE);
+       register_opcode_emulation (OP_FNEG, "__emul_fneg", "double double", mono_fneg, "mono_fneg", FALSE);
+       register_opcode_emulation (OP_ICONV_TO_R8, "__emul_iconv_to_r8", "double int32", mono_conv_to_r8, "mono_conv_to_r8", FALSE);
+       register_opcode_emulation (OP_ICONV_TO_R4, "__emul_iconv_to_r4", "double int32", mono_conv_to_r4, "mono_conv_to_r4", FALSE);
+       register_opcode_emulation (OP_FCONV_TO_R4, "__emul_fconv_to_r4", "double double", mono_fconv_r4, "mono_fconv_r4", FALSE);
+       register_opcode_emulation (OP_FCONV_TO_I1, "__emul_fconv_to_i1", "int8 double", mono_fconv_i1, "mono_fconv_i1", FALSE);
+       register_opcode_emulation (OP_FCONV_TO_I2, "__emul_fconv_to_i2", "int16 double", mono_fconv_i2, "mono_fconv_i2", FALSE);
+       register_opcode_emulation (OP_FCONV_TO_I4, "__emul_fconv_to_i4", "int32 double", mono_fconv_i4, "mono_fconv_i4", FALSE);
+       register_opcode_emulation (OP_FCONV_TO_U1, "__emul_fconv_to_u1", "uint8 double", mono_fconv_u1, "mono_fconv_u1", FALSE);
+       register_opcode_emulation (OP_FCONV_TO_U2, "__emul_fconv_to_u2", "uint16 double", mono_fconv_u2, "mono_fconv_u2", FALSE);
 #if SIZEOF_VOID_P == 4
-       mono_register_opcode_emulation (OP_FCONV_TO_I, "__emul_fconv_to_i", "int32 double", mono_fconv_i4, FALSE);
-#endif
-
-       mono_register_opcode_emulation (OP_FBEQ, "__emul_fcmp_eq", "uint32 double double", mono_fcmp_eq, FALSE);
-       mono_register_opcode_emulation (OP_FBLT, "__emul_fcmp_lt", "uint32 double double", mono_fcmp_lt, FALSE);
-       mono_register_opcode_emulation (OP_FBGT, "__emul_fcmp_gt", "uint32 double double", mono_fcmp_gt, FALSE);
-       mono_register_opcode_emulation (OP_FBLE, "__emul_fcmp_le", "uint32 double double", mono_fcmp_le, FALSE);
-       mono_register_opcode_emulation (OP_FBGE, "__emul_fcmp_ge", "uint32 double double", mono_fcmp_ge, FALSE);
-       mono_register_opcode_emulation (OP_FBNE_UN, "__emul_fcmp_ne_un", "uint32 double double", mono_fcmp_ne_un, FALSE);
-       mono_register_opcode_emulation (OP_FBLT_UN, "__emul_fcmp_lt_un", "uint32 double double", mono_fcmp_lt_un, FALSE);
-       mono_register_opcode_emulation (OP_FBGT_UN, "__emul_fcmp_gt_un", "uint32 double double", mono_fcmp_gt_un, FALSE);
-       mono_register_opcode_emulation (OP_FBLE_UN, "__emul_fcmp_le_un", "uint32 double double", mono_fcmp_le_un, FALSE);
-       mono_register_opcode_emulation (OP_FBGE_UN, "__emul_fcmp_ge_un", "uint32 double double", mono_fcmp_ge_un, FALSE);
-
-       mono_register_opcode_emulation (OP_FCEQ, "__emul_fcmp_ceq", "uint32 double double", mono_fceq, FALSE);
-       mono_register_opcode_emulation (OP_FCGT, "__emul_fcmp_cgt", "uint32 double double", mono_fcgt, FALSE);
-       mono_register_opcode_emulation (OP_FCGT_UN, "__emul_fcmp_cgt_un", "uint32 double double", mono_fcgt_un, FALSE);
-       mono_register_opcode_emulation (OP_FCLT, "__emul_fcmp_clt", "uint32 double double", mono_fclt, FALSE);
-       mono_register_opcode_emulation (OP_FCLT_UN, "__emul_fcmp_clt_un", "uint32 double double", mono_fclt_un, FALSE);
+       register_opcode_emulation (OP_FCONV_TO_I, "__emul_fconv_to_i", "int32 double", mono_fconv_i4, "mono_fconv_i4", FALSE);
+#endif
+
+       register_opcode_emulation (OP_FBEQ, "__emul_fcmp_eq", "uint32 double double", mono_fcmp_eq, "mono_fcmp_eq", FALSE);
+       register_opcode_emulation (OP_FBLT, "__emul_fcmp_lt", "uint32 double double", mono_fcmp_lt, "mono_fcmp_lt", FALSE);
+       register_opcode_emulation (OP_FBGT, "__emul_fcmp_gt", "uint32 double double", mono_fcmp_gt, "mono_fcmp_gt", FALSE);
+       register_opcode_emulation (OP_FBLE, "__emul_fcmp_le", "uint32 double double", mono_fcmp_le, "mono_fcmp_le", FALSE);
+       register_opcode_emulation (OP_FBGE, "__emul_fcmp_ge", "uint32 double double", mono_fcmp_ge, "mono_fcmp_ge", FALSE);
+       register_opcode_emulation (OP_FBNE_UN, "__emul_fcmp_ne_un", "uint32 double double", mono_fcmp_ne_un, "mono_fcmp_ne_un", FALSE);
+       register_opcode_emulation (OP_FBLT_UN, "__emul_fcmp_lt_un", "uint32 double double", mono_fcmp_lt_un, "mono_fcmp_lt_un", FALSE);
+       register_opcode_emulation (OP_FBGT_UN, "__emul_fcmp_gt_un", "uint32 double double", mono_fcmp_gt_un, "mono_fcmp_gt_un", FALSE);
+       register_opcode_emulation (OP_FBLE_UN, "__emul_fcmp_le_un", "uint32 double double", mono_fcmp_le_un, "mono_fcmp_le_un", FALSE);
+       register_opcode_emulation (OP_FBGE_UN, "__emul_fcmp_ge_un", "uint32 double double", mono_fcmp_ge_un, "mono_fcmp_ge_un", FALSE);
+
+       register_opcode_emulation (OP_FCEQ, "__emul_fcmp_ceq", "uint32 double double", mono_fceq, "mono_fceq", FALSE);
+       register_opcode_emulation (OP_FCGT, "__emul_fcmp_cgt", "uint32 double double", mono_fcgt, "mono_fcgt", FALSE);
+       register_opcode_emulation (OP_FCGT_UN, "__emul_fcmp_cgt_un", "uint32 double double", mono_fcgt_un, "mono_fcgt_un", FALSE);
+       register_opcode_emulation (OP_FCLT, "__emul_fcmp_clt", "uint32 double double", mono_fclt, "mono_fclt", FALSE);
+       register_opcode_emulation (OP_FCLT_UN, "__emul_fcmp_clt_un", "uint32 double double", mono_fclt_un, "mono_fclt_un", FALSE);
 
        register_icall (mono_fload_r4, "mono_fload_r4", "double ptr", FALSE);
        register_icall (mono_fstore_r4, "mono_fstore_r4", "void double ptr", FALSE);
@@ -6712,7 +7043,7 @@ mini_init (const char *filename, const char *runtime_version)
 #endif
 
 #if SIZEOF_REGISTER == 4
-       mono_register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", "uint32 double", mono_fconv_u4, TRUE);
+       register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", "uint32 double", mono_fconv_u4, "mono_fconv_u4", TRUE);
 #endif
 
        /* other jit icalls */
@@ -6724,7 +7055,7 @@ mini_init (const char *filename, const char *runtime_version)
                "ptr ptr ptr ptr", FALSE);
        register_icall (mono_get_special_static_data, "mono_get_special_static_data", "ptr int", FALSE);
        register_icall (mono_ldstr, "mono_ldstr", "object ptr ptr int32", FALSE);
-       register_icall (mono_helper_stelem_ref_check, "helper_stelem_ref_check", "void object object", FALSE);
+       register_icall (mono_helper_stelem_ref_check, "mono_helper_stelem_ref_check", "void object object", FALSE);
        register_icall (mono_object_new, "mono_object_new", "object ptr ptr", FALSE);
        register_icall (mono_object_new_specific, "mono_object_new_specific", "object ptr", FALSE);
        register_icall (mono_array_new, "mono_array_new", "object ptr ptr int32", FALSE);
@@ -6733,10 +7064,10 @@ mini_init (const char *filename, const char *runtime_version)
        register_icall (mono_ldftn, "mono_ldftn", "ptr ptr", FALSE);
        register_icall (mono_ldvirtfn, "mono_ldvirtfn", "ptr object ptr", FALSE);
        register_icall (mono_ldvirtfn_gshared, "mono_ldvirtfn_gshared", "ptr object ptr", FALSE);
-       register_icall (mono_helper_compile_generic_method, "compile_generic_method", "ptr object ptr ptr", FALSE);
-       register_icall (mono_helper_ldstr, "helper_ldstr", "object ptr int", FALSE);
-       register_icall (mono_helper_ldstr_mscorlib, "helper_ldstr_mscorlib", "object int", FALSE);
-       register_icall (mono_helper_newobj_mscorlib, "helper_newobj_mscorlib", "object int", FALSE);
+       register_icall (mono_helper_compile_generic_method, "mono_helper_compile_generic_method", "ptr object ptr ptr", FALSE);
+       register_icall (mono_helper_ldstr, "mono_helper_ldstr", "object ptr int", FALSE);
+       register_icall (mono_helper_ldstr_mscorlib, "mono_helper_ldstr_mscorlib", "object int", FALSE);
+       register_icall (mono_helper_newobj_mscorlib, "mono_helper_newobj_mscorlib", "object int", FALSE);
        register_icall (mono_value_copy, "mono_value_copy", "void ptr ptr ptr", FALSE);
        register_icall (mono_object_castclass, "mono_object_castclass", "object object ptr", FALSE);
        register_icall (mono_break, "mono_break", NULL, TRUE);
@@ -6746,8 +7077,11 @@ mini_init (const char *filename, const char *runtime_version)
        register_icall (mono_array_new_1, "mono_array_new_1", "object ptr int", FALSE);
        register_icall (mono_array_new_2, "mono_array_new_2", "object ptr int int", FALSE);
        register_icall (mono_array_new_3, "mono_array_new_3", "object ptr int int int", FALSE);
+       register_icall (mono_array_new_4, "mono_array_new_4", "object ptr int 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_object_gethashcode_gsharedvt, "mono_object_gethashcode_gsharedvt", "int ptr ptr ptr", TRUE);
 
        register_icall (mono_gc_wbarrier_value_copy_bitmap, "mono_gc_wbarrier_value_copy_bitmap", "void ptr ptr int int", FALSE);
 
@@ -6755,7 +7089,10 @@ mini_init (const char *filename, const char *runtime_version)
        register_icall (mono_object_isinst_with_cache, "mono_object_isinst_with_cache", "object object ptr ptr", FALSE);
 
        register_icall (mono_debugger_agent_user_break, "mono_debugger_agent_user_break", "void", FALSE);
+#endif
 
+#ifdef TARGET_IOS
+       register_icall (pthread_getspecific, "pthread_getspecific", NULL, TRUE);
 #endif
 
        mono_generic_sharing_init ();
@@ -6818,6 +7155,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);
@@ -6925,14 +7263,17 @@ mini_cleanup (MonoDomain *domain)
        DeleteCriticalSection (&jit_mutex);
 
        DeleteCriticalSection (&mono_delegate_section);
+
+#ifdef USE_JUMP_TABLES
+       mono_jumptable_cleanup ();
+#endif
 }
 
 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
@@ -6946,6 +7287,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
@@ -7002,10 +7346,12 @@ mono_precompile_assembly (MonoAssembly *ass, void *user_data)
                        invoke = mono_marshal_get_runtime_invoke (method, FALSE);
                        mono_compile_method (invoke);
                }
-               if (method->klass->marshalbyref && mono_method_signature (method)->hasthis) {
+#ifndef DISABLE_REMOTING
+               if (mono_class_is_marshalbyref (method->klass) && mono_method_signature (method)->hasthis) {
                        invoke = mono_marshal_get_remoting_invoke_with_check (method);
                        mono_compile_method (invoke);
                }
+#endif
        }
 
        /* Load and precompile referenced assemblies as well */
@@ -7050,3 +7396,148 @@ 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
+
+#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
+
+#ifdef USE_JUMP_TABLES
+#define DEFAULT_JUMPTABLE_CHUNK_ELEMENTS 128
+
+typedef struct MonoJumpTableChunk {
+       guint32 total;
+       guint32 active;
+       struct MonoJumpTableChunk *previous;
+       /* gpointer entries[total]; */
+} MonoJumpTableChunk;
+
+static MonoJumpTableChunk* g_jumptable = NULL;
+#define mono_jumptable_lock() EnterCriticalSection (&jumptable_mutex)
+#define mono_jumptable_unlock() LeaveCriticalSection (&jumptable_mutex)
+static CRITICAL_SECTION jumptable_mutex;
+
+static  MonoJumpTableChunk*
+mono_create_jumptable_chunk (guint32 max_entries)
+{
+       guint32 size = sizeof (MonoJumpTableChunk) + max_entries * sizeof(gpointer);
+       MonoJumpTableChunk *chunk = (MonoJumpTableChunk*) g_new0 (guchar, size);
+       chunk->total = max_entries;
+       return chunk;
+}
+
+void
+mono_jumptable_init (void)
+{
+       if (g_jumptable == NULL) {
+               InitializeCriticalSection (&jumptable_mutex);
+               g_jumptable = mono_create_jumptable_chunk (DEFAULT_JUMPTABLE_CHUNK_ELEMENTS);
+       }
+}
+
+gpointer*
+mono_jumptable_add_entry (void)
+{
+       return mono_jumptable_add_entries (1);
+}
+
+gpointer*
+mono_jumptable_add_entries (guint32 entries)
+{
+       guint32 index;
+       gpointer *result;
+
+       mono_jumptable_init ();
+       mono_jumptable_lock ();
+       index = g_jumptable->active;
+       if (index + entries >= g_jumptable->total) {
+               /*
+                * Grow jumptable, by adding one more chunk.
+                * We cannot realloc jumptable, as there could be pointers
+                * to existing jump table entries in the code, so instead
+                * we just add one more chunk.
+                */
+               guint32 max_entries = entries;
+               MonoJumpTableChunk *new_chunk;
+
+               if (max_entries < DEFAULT_JUMPTABLE_CHUNK_ELEMENTS)
+                       max_entries = DEFAULT_JUMPTABLE_CHUNK_ELEMENTS;
+               new_chunk = mono_create_jumptable_chunk (max_entries);
+               /* Link old jumptable, so that we could free it up later. */
+               new_chunk->previous = g_jumptable;
+               g_jumptable = new_chunk;
+               index = 0;
+       }
+       g_jumptable->active = index + entries;
+       result = (gpointer*)((guchar*)g_jumptable + sizeof(MonoJumpTableChunk)) + index;
+       mono_jumptable_unlock();
+
+       return result;
+}
+
+void
+mono_jumptable_cleanup (void)
+{
+       if (g_jumptable) {
+               MonoJumpTableChunk *current = g_jumptable, *prev;
+               while (current != NULL) {
+                       prev = current->previous;
+                       g_free (current);
+                       current = prev;
+               }
+               g_jumptable = NULL;
+               DeleteCriticalSection (&jumptable_mutex);
+       }
+}
+
+gpointer*
+mono_jumptable_get_entry (guint8 *code_ptr)
+{
+       return mono_arch_jumptable_entry_from_code (code_ptr);
+}
+#endif