Merge pull request #495 from nicolas-raoul/fix-for-issue2907-with-no-formatting-changes
[mono.git] / mono / mini / mini.c
index 261ab3e4dfefaa0878860f62d2e66eaa3d66eb84..a80150fa634f52978c3dacb5f6f61fb61d00a97f 100644 (file)
@@ -601,6 +601,35 @@ mono_tramp_info_free (MonoTrampInfo *info)
        g_free (info);
 }
 
+G_GNUC_UNUSED static void
+break_count (void)
+{
+}
+
+/*
+ * Runtime debugging tool, use if (debug_count ()) <x> else <y> to do <x> the first COUNT times, then do <y> afterwards.
+ * Set a breakpoint in break_count () to break the last time <x> is done.
+ */
+G_GNUC_UNUSED gboolean
+mono_debug_count (void)
+{
+       static int count = 0;
+       count ++;
+
+       if (!getenv ("COUNT"))
+               return TRUE;
+
+       if (count == atoi (getenv ("COUNT"))) {
+               break_count ();
+       }
+
+       if (count > atoi (getenv ("COUNT"))) {
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
 #define MONO_INIT_VARINFO(vi,id) do { \
        (vi)->range.first_use.pos.bid = 0xffff; \
        (vi)->reg = -1; \
@@ -2574,10 +2603,17 @@ mono_set_lmf_addr (gpointer lmf_addr)
 #endif
 }
 
-/* Called by native->managed wrappers */
-void
+/*
+ * mono_jit_thread_attach:
+ *
+ * Called by native->managed wrappers. Returns the original domain which needs to be
+ * restored, or NULL.
+ */
+MonoDomain*
 mono_jit_thread_attach (MonoDomain *domain)
 {
+       MonoDomain *orig;
+
        if (!domain)
                /* 
                 * Happens when called from AOTed code which is only used in the root
@@ -2597,10 +2633,21 @@ mono_jit_thread_attach (MonoDomain *domain)
                mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background);
        }
 #endif
-       if (mono_domain_get () != domain)
-               mono_domain_set (domain, TRUE);
+       orig = mono_domain_get ();
+       if (orig != domain)
+               mono_domain_set (domain, TRUE);
+
+       return orig != domain ? orig : NULL;
 }      
 
+/* Called by native->managed wrappers */
+void
+mono_jit_set_domain (MonoDomain *domain)
+{
+       if (domain)
+               mono_domain_set (domain, TRUE);
+}
+
 /**
  * mono_thread_abort:
  * @obj: exception object
@@ -2619,16 +2666,7 @@ mono_thread_abort (MonoObject *obj)
                        (obj->vtable->klass == mono_defaults.threadabortexception_class)) {
                mono_thread_exit ();
        } else {
-               MonoObject *other = NULL;
-               MonoString *str = mono_object_to_string (obj, &other);
-               if (str) {
-                       char *msg = mono_string_to_utf8 (str);
-                       fprintf (stderr, "[ERROR] FATAL UNHANDLED EXCEPTION: %s\n", msg);
-                       fflush (stderr);
-                       g_free (msg);
-               }
-
-               exit (mono_environment_exitcode_get ());
+               mono_invoke_unhandled_exception_hook (obj);
        }
 }
 
@@ -2784,6 +2822,12 @@ mono_get_thread_intrinsic (MonoCompile* cfg)
        return mono_create_tls_get (cfg, mono_thread_get_tls_offset ());
 }
 
+MonoInst*
+mono_get_lmf_intrinsic (MonoCompile* cfg)
+{
+       return mono_create_tls_get (cfg, mono_get_lmf_tls_offset ());
+}
+
 void
 mono_add_patch_info (MonoCompile *cfg, int ip, MonoJumpInfoType type, gconstpointer target)
 {
@@ -3147,10 +3191,16 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
        case MONO_PATCH_INFO_ICALL_ADDR:
                /* run_cctors == 0 -> AOT */
                if (patch_info->data.method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
+                       const char *exc_class;
+                       const char *exc_arg;
+
                        if (run_cctors) {
-                               target = mono_lookup_pinvoke_call (patch_info->data.method, NULL, NULL);
-                               if (!target)
+                               target = mono_lookup_pinvoke_call (patch_info->data.method, &exc_class, &exc_arg);
+                               if (!target) {
+                                       if (mono_aot_only)
+                                               mono_raise_exception (mono_exception_from_name_msg (mono_defaults.corlib, "System", exc_class, exc_arg));
                                        g_error ("Unable to resolve pinvoke method '%s' Re-run with MONO_LOG_LEVEL=debug for more information.\n", mono_method_full_name (patch_info->data.method, TRUE));
+                               }
                        } else {
                                target = NULL;
                        }
@@ -3191,14 +3241,14 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
 
                switch (entry->data->type) {
                case MONO_PATCH_INFO_CLASS:
-                       slot = mono_method_lookup_or_register_other_info (entry->method, entry->in_mrgctx, &entry->data->data.klass->byval_arg, entry->info_type, mono_method_get_context (entry->method));
+                       slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, &entry->data->data.klass->byval_arg, entry->info_type, mono_method_get_context (entry->method));
                        break;
                case MONO_PATCH_INFO_METHOD:
                case MONO_PATCH_INFO_METHODCONST:
-                       slot = mono_method_lookup_or_register_other_info (entry->method, entry->in_mrgctx, entry->data->data.method, entry->info_type, mono_method_get_context (entry->method));
+                       slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, entry->data->data.method, entry->info_type, mono_method_get_context (entry->method));
                        break;
                case MONO_PATCH_INFO_FIELD:
-                       slot = mono_method_lookup_or_register_other_info (entry->method, entry->in_mrgctx, entry->data->data.field, entry->info_type, mono_method_get_context (entry->method));
+                       slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, entry->data->data.field, entry->info_type, mono_method_get_context (entry->method));
                        break;
                default:
                        g_assert_not_reached ();
@@ -3544,6 +3594,29 @@ mono_save_seq_point_info (MonoCompile *cfg)
 
                        last = ins;
                }
+
+               if (bb->last_ins && bb->last_ins->opcode == OP_ENDFINALLY) {
+                       MonoBasicBlock *bb2;
+                       MonoInst *endfinally_seq_point = NULL;
+
+                       /*
+                        * The ENDFINALLY branches are not represented in the cfg, so link it with all seq points starting bbs.
+                        */
+                       l = g_slist_last (bb->seq_points);
+                       g_assert (l);
+                       endfinally_seq_point = l->data;
+
+                       for (bb2 = cfg->bb_entry; bb2; bb2 = bb2->next_bb) {
+                               GSList *l = g_slist_last (bb2->seq_points);
+
+                               if (l) {
+                                       MonoInst *ins = l->data;
+
+                                       if (!(ins->inst_imm == METHOD_ENTRY_IL_OFFSET || ins->inst_imm == METHOD_EXIT_IL_OFFSET) && ins != endfinally_seq_point)
+                                               next [endfinally_seq_point->backend.size] = g_slist_append (next [endfinally_seq_point->backend.size], GUINT_TO_POINTER (ins->backend.size));
+                               }
+                       }
+               }
        }
 
        if (cfg->verbose_level > 2) {
@@ -3559,10 +3632,10 @@ mono_save_seq_point_info (MonoCompile *cfg)
                sp->next = g_new (int, sp->next_len);
                j = 0;
                if (cfg->verbose_level > 2 && next [i]) {
-                       printf ("\t0x%x ->", sp->il_offset);
+                       printf ("\tIL0x%x ->", sp->il_offset);
                        for (l = next [i]; l; l = l->next) {
                                next_index = GPOINTER_TO_UINT (l->data);
-                               printf (" 0x%x", info->seq_points [next_index].il_offset);
+                               printf (" IL0x%x", info->seq_points [next_index].il_offset);
                        }
                        printf ("\n");
                }
@@ -3830,7 +3903,7 @@ create_jit_info (MonoCompile *cfg, MonoMethod *method_to_compile)
        MonoJitInfo *jinfo;
        int num_clauses;
        int generic_info_size, arch_eh_info_size = 0;
-       int holes_size = 0, num_holes = 0;
+       int holes_size = 0, num_holes = 0, cas_size = 0;
        guint32 stack_size = 0;
 
        g_assert (method_to_compile == cfg->method);
@@ -3850,7 +3923,7 @@ create_jit_info (MonoCompile *cfg, MonoMethod *method_to_compile)
                 * mono_arch_get_argument_info () is not signal safe.
                 */
                arg_info = g_newa (MonoJitArgumentInfo, sig->param_count + 1);
-               stack_size = mono_arch_get_argument_info (sig, sig->param_count, arg_info);
+               stack_size = mono_arch_get_argument_info (cfg->generic_sharing_context, sig, sig->param_count, arg_info);
 
                if (stack_size)
                        arch_eh_info_size = sizeof (MonoArchEHJitInfo);
@@ -3874,6 +3947,10 @@ create_jit_info (MonoCompile *cfg, MonoMethod *method_to_compile)
                        printf ("Number of try block holes %d\n", num_holes);
        }
 
+       if (mono_method_has_declsec (cfg->method_to_register)) {
+               cas_size = sizeof (MonoMethodCasInfo);
+       }
+
        if (COMPILE_LLVM (cfg))
                num_clauses = cfg->llvm_ex_info_len;
        else
@@ -3881,11 +3958,11 @@ create_jit_info (MonoCompile *cfg, MonoMethod *method_to_compile)
 
        if (cfg->method->dynamic) {
                jinfo = g_malloc0 (MONO_SIZEOF_JIT_INFO + (num_clauses * sizeof (MonoJitExceptionInfo)) +
-                               generic_info_size + holes_size + arch_eh_info_size);
+                               generic_info_size + holes_size + arch_eh_info_size + cas_size);
        } else {
                jinfo = mono_domain_alloc0 (cfg->domain, MONO_SIZEOF_JIT_INFO +
                                (num_clauses * sizeof (MonoJitExceptionInfo)) +
-                               generic_info_size + holes_size + arch_eh_info_size);
+                               generic_info_size + holes_size + arch_eh_info_size + cas_size);
        }
 
        jinfo->method = cfg->method_to_register;
@@ -3893,8 +3970,8 @@ create_jit_info (MonoCompile *cfg, MonoMethod *method_to_compile)
        jinfo->code_size = cfg->code_len;
        jinfo->used_regs = cfg->used_int_regs;
        jinfo->domain_neutral = (cfg->opt & MONO_OPT_SHARED) != 0;
-       jinfo->cas_inited = FALSE; /* initialization delayed at the first stalk walk using this method */
        jinfo->num_clauses = num_clauses;
+
        if (COMPILE_LLVM (cfg))
                jinfo->from_llvm = TRUE;
 
@@ -4012,6 +4089,10 @@ create_jit_info (MonoCompile *cfg, MonoMethod *method_to_compile)
                info->stack_size = stack_size;
        }
 
+       if (cas_size) {
+               jinfo->has_cas_info = 1;
+       }
+
        if (COMPILE_LLVM (cfg)) {
                if (num_clauses)
                        memcpy (&jinfo->clauses [0], &cfg->llvm_ex_info [0], num_clauses * sizeof (MonoJitExceptionInfo));
@@ -4225,7 +4306,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        InterlockedIncrement (&mono_jit_stats.methods_compiled);
        if (mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION)
                mono_profiler_method_jit (method);
-       if (MONO_PROBE_METHOD_COMPILE_BEGIN_ENABLED ())
+       if (MONO_METHOD_COMPILE_BEGIN_ENABLED ())
                MONO_PROBE_METHOD_COMPILE_BEGIN (method);
 
        if (compile_aot)
@@ -4301,7 +4382,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
                cfg->exception_type = MONO_EXCEPTION_TYPE_LOAD;
                cfg->exception_message = g_strdup (mono_error_get_message (&err));
                mono_error_cleanup (&err);
-               if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
+               if (MONO_METHOD_COMPILE_END_ENABLED ())
                        MONO_PROBE_METHOD_COMPILE_END (method, FALSE);
                return cfg;
        }
@@ -4316,7 +4397,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
                        cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
                        cfg->exception_message = g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name);
                }
-               if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
+               if (MONO_METHOD_COMPILE_END_ENABLED ())
                        MONO_PROBE_METHOD_COMPILE_END (method, FALSE);
                return cfg;
        }
@@ -4520,7 +4601,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        if (i < 0) {
                if (try_generic_shared && cfg->exception_type == MONO_EXCEPTION_GENERIC_SHARING_FAILED) {
                        if (compile_aot) {
-                               if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
+                               if (MONO_METHOD_COMPILE_END_ENABLED ())
                                        MONO_PROBE_METHOD_COMPILE_END (method, FALSE);
                                return cfg;
                        }
@@ -4530,7 +4611,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
                }
                g_assert (cfg->exception_type != MONO_EXCEPTION_GENERIC_SHARING_FAILED);
 
-               if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
+               if (MONO_METHOD_COMPILE_END_ENABLED ())
                        MONO_PROBE_METHOD_COMPILE_END (method, FALSE);
                /* cfg contains the details of the failure, so let the caller cleanup */
                return cfg;
@@ -4653,7 +4734,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
 
        /* after method_to_ir */
        if (parts == 1) {
-               if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
+               if (MONO_METHOD_COMPILE_END_ENABLED ())
                        MONO_PROBE_METHOD_COMPILE_END (method, TRUE);
                return cfg;
        }
@@ -4690,7 +4771,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
 
        /* after SSA translation */
        if (parts == 2) {
-               if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
+               if (MONO_METHOD_COMPILE_END_ENABLED ())
                        MONO_PROBE_METHOD_COMPILE_END (method, TRUE);
                return cfg;
        }
@@ -4757,7 +4838,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
 
        /* after SSA removal */
        if (parts == 3) {
-               if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
+               if (MONO_METHOD_COMPILE_END_ENABLED ())
                        MONO_PROBE_METHOD_COMPILE_END (method, TRUE);
                return cfg;
        }
@@ -4979,8 +5060,10 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        }
 
        /* 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) {
@@ -4996,7 +5079,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        }
        mono_jit_stats.native_code_size += cfg->code_len;
 
-       if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
+       if (MONO_METHOD_COMPILE_END_ENABLED ())
                MONO_PROBE_METHOD_COMPILE_END (method, TRUE);
 
        return cfg;
@@ -5209,7 +5292,7 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
 
        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);
@@ -5447,6 +5530,14 @@ mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, MonoException
        else 
                target_domain = domain;
 
+       if (method->wrapper_type == MONO_WRAPPER_UNKNOWN) {
+               WrapperInfo *info = mono_marshal_get_wrapper_info (method);
+
+               g_assert (info);
+               if (info->subtype == WRAPPER_SUBTYPE_SYNCHRONIZED_INNER)
+                       method = info->d.synchronized_inner.method;
+       }
+
        info = lookup_method (target_domain, method);
        if (info) {
                /* We can't use a domain specific method in another domain */
@@ -5508,7 +5599,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
@@ -6283,7 +6374,7 @@ mini_init (const char *filename, const char *runtime_version)
        MonoRuntimeCallbacks callbacks;
        MonoThreadInfoRuntimeCallbacks ticallbacks;
 
-       MONO_PROBE_VES_INIT_BEGIN ();
+       MONO_VES_INIT_BEGIN ();
 
 #if defined(__linux__) && !defined(__native_client__)
        if (access ("/proc/self/maps", F_OK) != 0) {
@@ -6384,7 +6475,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 ();
@@ -6441,6 +6531,7 @@ mini_init (const char *filename, const char *runtime_version)
        if (mono_aot_only) {
                /* This helps catch code allocation requests */
                mono_code_manager_set_read_only (domain->code_mp);
+               mono_marshal_use_aot_wrappers (TRUE);
        }
 
 #ifdef MONO_ARCH_HAVE_IMT
@@ -6476,6 +6567,11 @@ mini_init (const char *filename, const char *runtime_version)
        mono_add_internal_call ("Mono.Runtime::mono_runtime_install_handlers", 
                                mono_runtime_install_handlers);
 
+#ifdef PLATFORM_ANDROID
+       mono_add_internal_call ("System.Diagnostics.Debugger::Mono_UnhandledException_internal",
+                               mono_debugger_agent_unhandled_exception);
+#endif
+
        mono_create_helper_signatures ();
 
        register_jit_stats ();
@@ -6491,7 +6587,8 @@ mini_init (const char *filename, const char *runtime_version)
        register_icall (mono_trace_enter_method, "mono_trace_enter_method", NULL, TRUE);
        register_icall (mono_trace_leave_method, "mono_trace_leave_method", NULL, TRUE);
        register_icall (mono_get_lmf_addr, "mono_get_lmf_addr", "ptr", TRUE);
-       register_icall (mono_jit_thread_attach, "mono_jit_thread_attach", "void", TRUE);
+       register_icall (mono_jit_thread_attach, "mono_jit_thread_attach", "ptr ptr", TRUE);
+       register_icall (mono_jit_set_domain, "mono_jit_set_domain", "void ptr", TRUE);
        register_icall (mono_domain_get, "mono_domain_get", "ptr", TRUE);
 
        register_icall (mono_get_throw_exception (), "mono_arch_throw_exception", "void object", TRUE);
@@ -6693,7 +6790,7 @@ mini_init (const char *filename, const char *runtime_version)
 
        mono_profiler_runtime_initialized ();
 
-       MONO_PROBE_VES_INIT_END ();
+       MONO_VES_INIT_END ();
        
        return domain;
 }
@@ -6746,10 +6843,6 @@ print_jit_stats (void)
                g_print ("JIT info table lookups: %ld\n", mono_stats.jit_info_table_lookup_count);
 
                g_print ("Hazardous pointers:     %ld\n", mono_stats.hazardous_pointer_count);
-               g_print ("Minor GC collections:   %ld\n", mono_stats.minor_gc_count);
-               g_print ("Major GC collections:   %ld\n", mono_stats.major_gc_count);
-               g_print ("Minor GC time in msecs: %lf\n", (double)mono_stats.minor_gc_time_usecs / 1000.0);
-               g_print ("Major GC time in msecs: %lf\n", (double)mono_stats.major_gc_time_usecs / 1000.0);
                if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
                        g_print ("\nDecl security check   : %ld\n", mono_jit_stats.cas_declsec_check);
                        g_print ("LinkDemand (user)     : %ld\n", mono_jit_stats.cas_linkdemand);
@@ -6870,11 +6963,12 @@ mono_set_verbose_level (guint32 level)
        mini_verbose = level;
 }
 
-/*
+/**
  * mono_get_runtime_build_info:
  *
- *   Return the runtime version + build date in string format.
- * The returned string is owned by the caller.
+ * Return the runtime version + build date in string format.
+ * The returned string is owned by the caller. The returned string
+ * format is "VERSION (FULL_VERSION BUILD_DATE)" and build date is optional.
  */
 char*
 mono_get_runtime_build_info (void)