Merge pull request #1708 from alexanderkyte/always_use_imt
[mono.git] / mono / mini / mini-runtime.c
index 756806b601dd6af8ff7fcbc34c851e27d2abbc44..c0943117994ef469b57b90cd38a9dc3ce5f561a9 100755 (executable)
@@ -86,8 +86,7 @@ MONO_FAST_TLS_DECLARE(mono_jit_tls);
 gboolean mono_compile_aot = FALSE;
 /* If this is set, no code is generated dynamically, everything is taken from AOT files */
 gboolean mono_aot_only = FALSE;
-/* Whenever to use IMT */
-gboolean mono_use_imt = TRUE;
+
 const char *mono_build_date;
 gboolean mono_do_signal_chaining;
 gboolean mono_do_crash_chaining;
@@ -609,14 +608,6 @@ mono_icall_get_wrapper (MonoJitICallInfo* callinfo)
        return mono_icall_get_wrapper_full (callinfo, FALSE);
 }
 
-static void
-mono_dynamic_code_hash_insert (MonoDomain *domain, MonoMethod *method, MonoJitDynamicMethodInfo *ji)
-{
-       if (!domain_jit_info (domain)->dynamic_code_hash)
-               domain_jit_info (domain)->dynamic_code_hash = g_hash_table_new (NULL, NULL);
-       g_hash_table_insert (domain_jit_info (domain)->dynamic_code_hash, method, ji);
-}
-
 static MonoJitDynamicMethodInfo*
 mono_dynamic_code_hash_lookup (MonoDomain *domain, MonoMethod *method)
 {
@@ -654,20 +645,6 @@ register_icall (gpointer func, const char *name, const char *sigstr, gboolean sa
        mono_register_jit_icall_full (func, name, sig, save, FALSE, save ? name : NULL);
 }
 
-/* Register a jit icall which doesn't throw exceptions through mono_raise_exception () */
-static void
-register_icall_noraise (gpointer func, const char *name, const char *sigstr)
-{
-       MonoMethodSignature *sig;
-
-       if (sigstr)
-               sig = mono_create_icall_signature (sigstr);
-       else
-               sig = NULL;
-
-       mono_register_jit_icall_full (func, name, sig, TRUE, TRUE, name);
-}
-
 static void
 register_dyn_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
 {
@@ -947,9 +924,9 @@ free_jit_tls_data (MonoJitTlsData *jit_tls)
 static void
 mono_thread_start_cb (intptr_t tid, gpointer stack_start, gpointer func)
 {
-       MonoInternalThread *thread;
+       MonoThreadInfo *thread;
        void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort);
-       thread = mono_thread_internal_current ();
+       thread = mono_thread_info_current_unchecked ();
        if (thread)
                thread->jit_data = jit_tls;
 
@@ -970,9 +947,9 @@ mono_thread_abort_dummy (MonoObject *obj)
 static void
 mono_thread_attach_cb (intptr_t tid, gpointer stack_start)
 {
-       MonoInternalThread *thread;
+       MonoThreadInfo *thread;
        void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort_dummy);
-       thread = mono_thread_internal_current ();
+       thread = mono_thread_info_current_unchecked ();
        if (thread)
                thread->jit_data = jit_tls;
        if (mono_profiler_get_events () & MONO_PROFILE_STATISTICAL)
@@ -982,30 +959,41 @@ mono_thread_attach_cb (intptr_t tid, gpointer stack_start)
 }
 
 static void
-mini_thread_cleanup (MonoInternalThread *thread)
+mini_thread_cleanup (MonoNativeThreadId tid)
 {
-       MonoJitTlsData *jit_tls = thread->jit_data;
+       MonoJitTlsData *jit_tls = NULL;
+       MonoThreadInfo *info;
 
-       if (jit_tls) {
-               /* We can't clean up tls information if we are on another thread, it will clean up the wrong stuff
-                * It would be nice to issue a warning when this happens outside of the shutdown sequence. but it's
-                * not a trivial thing.
-                *
-                * The current offender is mono_thread_manage which cleanup threads from the outside.
-                */
-               if (thread == mono_thread_internal_current ())
-                       mono_set_jit_tls (NULL);
+       info = mono_thread_info_current_unchecked ();
+
+       /* We can't clean up tls information if we are on another thread, it will clean up the wrong stuff
+        * It would be nice to issue a warning when this happens outside of the shutdown sequence. but it's
+        * not a trivial thing.
+        *
+        * The current offender is mono_thread_manage which cleanup threads from the outside.
+        */
+       if (info && mono_thread_info_get_tid (info) == tid) {
+               jit_tls = info->jit_data;
+               info->jit_data = NULL;
+
+               mono_set_jit_tls (NULL);
 
                /* If we attach a thread but never call into managed land, we might never get an lmf.*/
                if (mono_get_lmf ()) {
                        mono_set_lmf (NULL);
                        mono_set_lmf_addr (NULL);
                }
+       } else {
+               info = mono_thread_info_lookup (tid);
+               if (info) {
+                       jit_tls = info->jit_data;
+                       info->jit_data = NULL;
+               }
+               mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
+       }
 
+       if (jit_tls)
                free_jit_tls_data (jit_tls);
-
-               thread->jit_data = NULL;
-       }
 }
 
 int
@@ -1119,6 +1107,16 @@ mono_patch_info_dup_mp (MonoMemPool *mp, MonoJumpInfo *patch_info)
                //memcpy (info->locals_types, oinfo->locals_types, info->nlocals * sizeof (MonoType*));
                break;
        }
+       case MONO_PATCH_INFO_VIRT_METHOD: {
+               MonoJumpInfoVirtMethod *info;
+               MonoJumpInfoVirtMethod *oinfo;
+
+               oinfo = patch_info->data.virt_method;
+               info = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoVirtMethod));
+               res->data.virt_method = info;
+               memcpy (info, oinfo, sizeof (MonoJumpInfoVirtMethod));
+               break;
+       }
        default:
                break;
        }
@@ -1171,6 +1169,7 @@ mono_patch_info_hash (gconstpointer data)
        case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG:
        case MONO_PATCH_INFO_MSCORLIB_GOT_ADDR:
        case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR:
+       case MONO_PATCH_INFO_GC_NURSERY_START:
        case MONO_PATCH_INFO_JIT_TLS_ID:
        case MONO_PATCH_INFO_MONITOR_ENTER:
        case MONO_PATCH_INFO_MONITOR_ENTER_V4:
@@ -1190,6 +1189,11 @@ mono_patch_info_hash (gconstpointer data)
                return (ji->type << 8) | (gsize)ji->data.del_tramp->klass | (gsize)ji->data.del_tramp->method | (gsize)ji->data.del_tramp->virtual;
        case MONO_PATCH_INFO_LDSTR_LIT:
                return g_str_hash (ji->data.target);
+       case MONO_PATCH_INFO_VIRT_METHOD: {
+               MonoJumpInfoVirtMethod *info = ji->data.virt_method;
+
+               return (ji->type << 8) | (gssize)info->klass | (gssize)info->method;
+       }
        default:
                printf ("info type: %d\n", ji->type);
                mono_print_ji (ji); printf ("\n");
@@ -1247,6 +1251,8 @@ mono_patch_info_equal (gconstpointer ka, gconstpointer kb)
                return ji1->data.del_tramp->klass == ji2->data.del_tramp->klass && ji1->data.del_tramp->method == ji2->data.del_tramp->method && ji1->data.del_tramp->virtual == ji2->data.del_tramp->virtual;
        case MONO_PATCH_INFO_CASTCLASS_CACHE:
                return ji1->data.index == ji2->data.index;
+       case MONO_PATCH_INFO_VIRT_METHOD:
+               return ji1->data.virt_method->klass == ji2->data.virt_method->klass && ji1->data.virt_method->method == ji2->data.virt_method->method;
        default:
                if (ji1->data.target != ji2->data.target)
                        return 0;
@@ -1584,6 +1590,15 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
                        slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
                        break;
                }
+               case MONO_PATCH_INFO_VIRT_METHOD: {
+                       MonoJumpInfoVirtMethod *info;
+                       MonoJumpInfoVirtMethod *oinfo = entry->data->data.virt_method;
+
+                       info = g_malloc0 (sizeof (MonoJumpInfoVirtMethod));
+                       memcpy (info, oinfo, sizeof (MonoJumpInfoVirtMethod));
+                       slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
+                       break;
+               }
                default:
                        g_assert_not_reached ();
                        break;
@@ -1628,6 +1643,13 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
                target = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
                break;
        }
+       case MONO_PATCH_INFO_GC_NURSERY_START: {
+               int shift_bits;
+               size_t size;
+
+               target = mono_gc_get_nursery (&shift_bits, &size);
+               break;
+       }
        case MONO_PATCH_INFO_CASTCLASS_CACHE: {
                target = mono_domain_alloc0 (domain, sizeof (gpointer));
                break;
@@ -1651,7 +1673,14 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
                break;
        }
        case MONO_PATCH_INFO_LDSTR_LIT: {
-               target = mono_string_new (domain, patch_info->data.target);
+               int len;
+               char *s;
+
+               len = strlen (patch_info->data.target);
+               s = mono_domain_alloc0 (domain, len + 1);
+               memcpy (s, patch_info->data.target, len);
+               target = s;
+
                break;
        }
        default:
@@ -1661,179 +1690,12 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
        return (gpointer)target;
 }
 
-static MonoType*
-get_gsharedvt_type (MonoType *t)
-{
-       MonoGenericParam *par = t->data.generic_param;
-       MonoGenericParam *copy;
-       MonoType *res;
-       MonoImage *image = NULL;
-
-       /*
-        * Create an anonymous gparam with a different gshared_constraint so normal gshared and gsharedvt methods have
-        * a different instantiation.
-        */
-       g_assert (mono_generic_param_info (par));
-       if (par->owner) {
-               image = par->owner->image;
-
-               mono_image_lock (image);
-               if (!image->gshared_types) {
-                       image->gshared_types_len = 1;
-                       image->gshared_types = g_new0 (GHashTable*, image->gshared_types_len);
-                       image->gshared_types [0] = g_hash_table_new (NULL, NULL);
-               }
-               res = g_hash_table_lookup (image->gshared_types [0], par);
-               mono_image_unlock (image);
-               if (res)
-                       return res;
-               copy = mono_image_alloc0 (image, sizeof (MonoGenericParamFull));
-               memcpy (copy, par, sizeof (MonoGenericParamFull));
-       } else {
-               copy = g_memdup (par, sizeof (MonoGenericParam));
-       }
-       copy->owner = NULL;
-       // FIXME:
-       copy->image = mono_defaults.corlib;
-       copy->gshared_constraint = MONO_TYPE_VALUETYPE;
-       res = mono_metadata_type_dup (NULL, t);
-       res->data.generic_param = copy;
-
-       if (par->owner) {
-               mono_image_lock (image);
-               /* Duplicates are ok */
-               g_hash_table_insert (image->gshared_types [0], par, res);
-               mono_image_unlock (image);
-       }
-
-       return res;
-}
-
 static gboolean
 is_gsharedvt_type (MonoType *t)
 {
        return (t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR) && t->data.generic_param->gshared_constraint == MONO_TYPE_VALUETYPE;
 }
 
-static gboolean
-is_open_method (MonoMethod *method)
-{
-       MonoGenericContext *context;
-
-       if (!method->is_inflated)
-               return FALSE;
-       context = mono_method_get_context (method);
-       if (context->class_inst && context->class_inst->is_open)
-               return TRUE;
-       if (context->method_inst && context->method_inst->is_open)
-               return TRUE;
-       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) {
-                       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_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_full (MonoMethod *method, gboolean all_vt, gboolean is_gsharedvt)
-{
-       MonoError error;
-       MonoGenericContext shared_context;
-       MonoMethod *declaring_method, *res;
-       gboolean partial = FALSE;
-       gboolean gsharedvt = FALSE;
-       MonoGenericContainer *class_container, *method_container = NULL;
-
-       if (method->is_generic || (method->klass->generic_container && !method->is_inflated)) {
-               declaring_method = method;
-       } 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 gsharedvt/partial sharing */
-       if ((method != declaring_method && method->is_inflated && !mono_method_is_generic_sharable_full (method, FALSE, FALSE, TRUE)) ||
-               is_gsharedvt || mini_is_gsharedvt_sharable_method (method)) {
-               MonoGenericContext *context = mono_method_get_context (method);
-               MonoGenericInst *inst;
-
-               partial = mono_method_is_generic_sharable_full (method, FALSE, TRUE, FALSE);
-
-               gsharedvt = is_gsharedvt || (!partial && 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.
-                */
-               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);
-
-               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);
-
-               partial = TRUE;
-       }
-
-    res = mono_class_inflate_generic_method_checked (declaring_method, &shared_context, &error);
-       g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
-
-       if (!partial) {
-               /* The result should be an inflated method whose parent is not inflated */
-               g_assert (!res->klass->is_inflated);
-       }
-       return res;
-}
-
-MonoMethod*
-mini_get_shared_method (MonoMethod *method)
-{
-       return mini_get_shared_method_full (method, FALSE, FALSE);
-}
-
 void
 mini_init_gsctx (MonoDomain *domain, MonoMemPool *mp, MonoGenericContext *context, MonoGenericSharingContext *gsctx)
 {
@@ -1927,6 +1789,12 @@ lookup_method (MonoDomain *domain, MonoMethod *method)
        return ji;
 }
 
+MonoJitInfo *
+mono_get_jit_info_from_method (MonoDomain *domain, MonoMethod *method)
+{
+       return lookup_method (domain, method);
+}
+
 #if ENABLE_JIT_MAP
 static FILE* perf_map_file;
 
@@ -2821,7 +2689,7 @@ mini_parse_debug_options (void)
                else if (!strcmp (arg, "explicit-null-checks"))
                        debug_options.explicit_null_checks = TRUE;
                else if (!strcmp (arg, "gen-seq-points"))
-                       debug_options.gen_seq_points_debug_data = TRUE;
+                       debug_options.gen_sdb_seq_points = TRUE;
                else if (!strcmp (arg, "gen-compact-seq-points"))
                        debug_options.gen_seq_points_compact_data = TRUE;
                else if (!strcmp (arg, "init-stacks"))
@@ -3115,10 +2983,8 @@ mini_init (const char *filename, const char *runtime_version)
        callbacks.debug_log_is_enabled = mono_debugger_agent_debug_log_is_enabled;
        callbacks.tls_key_supported = mini_tls_key_supported;
 
-       if (mono_use_imt) {
-               callbacks.get_vtable_trampoline = mini_get_vtable_trampoline;
-               callbacks.get_imt_trampoline = mini_get_imt_trampoline;
-       }
+       callbacks.get_vtable_trampoline = mini_get_vtable_trampoline;
+       callbacks.get_imt_trampoline = mini_get_imt_trampoline;
 
        mono_install_callbacks (&callbacks);
 
@@ -3144,6 +3010,7 @@ mini_init (const char *filename, const char *runtime_version)
 
        mono_unwind_init ();
 
+#ifdef XDEBUG_ENABLED
        if (g_getenv ("MONO_XDEBUG")) {
                const char *xdebug_opts = g_getenv ("MONO_XDEBUG");
                mono_xdebug_init (xdebug_opts);
@@ -3155,6 +3022,7 @@ mini_init (const char *filename, const char *runtime_version)
                mono_dont_free_domains = TRUE;
                mono_using_xdebug = TRUE;
        }
+#endif
 
 #ifdef ENABLE_LLVM
        if (mono_use_llvm) {
@@ -3225,12 +3093,10 @@ mini_init (const char *filename, const char *runtime_version)
                mono_marshal_use_aot_wrappers (TRUE);
        }
 
-       if (mono_use_imt) {
-               if (mono_aot_only)
-                       mono_install_imt_thunk_builder (mono_aot_get_imt_thunk);
-               else
-                       mono_install_imt_thunk_builder (mono_arch_build_imt_thunk);
-       }
+       if (mono_aot_only)
+               mono_install_imt_thunk_builder (mono_aot_get_imt_thunk);
+       else
+               mono_install_imt_thunk_builder (mono_arch_build_imt_thunk);
 
        /*Init arch tls information only after the metadata side is inited to make sure we see dynamic appdomain tls keys*/
        mono_arch_finish_init ();