2010-01-04 Rodrigo Kumpera <rkumpera@novell.com>
[mono.git] / mono / mini / mini.c
index 9ccfb86c19d8ce7f8231d88fdb6d47cf5b0dfc67..8f7772f061c59122749d858f932f804c045f139d 100644 (file)
@@ -21,9 +21,7 @@
 #include <sys/time.h>
 #endif
 
-#ifdef HAVE_VALGRIND_MEMCHECK_H
-#include <valgrind/memcheck.h>
-#endif
+#include <mono/utils/memcheck.h>
 
 #include <mono/metadata/assembly.h>
 #include <mono/metadata/loader.h>
@@ -163,17 +161,13 @@ gboolean mono_dont_free_global_codeman;
 gboolean
 mono_running_on_valgrind (void)
 {
-#ifdef HAVE_VALGRIND_MEMCHECK_H
-               if (RUNNING_ON_VALGRIND){
+       if (RUNNING_ON_VALGRIND){
 #ifdef VALGRIND_JIT_REGISTER_MAP
-                       valgrind_register = TRUE;
+               valgrind_register = TRUE;
 #endif
-                       return TRUE;
-               } else
-                       return FALSE;
-#else
+               return TRUE;
+       } else
                return FALSE;
-#endif
 }
 
 typedef struct {
@@ -655,7 +649,9 @@ mono_type_to_load_membase (MonoCompile *cfg, MonoType *type)
        if (type->byref)
                return OP_LOAD_MEMBASE;
 
-       switch (mono_type_get_underlying_type (type)->type) {
+       type = mono_type_get_underlying_type (type);
+
+       switch (type->type) {
        case MONO_TYPE_I1:
                return OP_LOADI1_MEMBASE;
        case MONO_TYPE_U1:
@@ -1301,6 +1297,23 @@ mini_method_verify (MonoCompile *cfg, MonoMethod *method)
        return FALSE;
 }
 
+/*Returns true is something went wrong*/
+static gboolean
+mono_compile_is_broken (MonoCompile *cfg)
+{
+       MonoMethod *method = cfg->method;
+       MonoMethod *method_definition = method;
+       gboolean dont_verify = mini_assembly_can_skip_verification (cfg->domain, method);
+       dont_verify |= method->klass->image->assembly->corlib_internal;
+
+       while (method_definition->is_inflated) {
+               MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
+               method_definition = imethod->declaring;
+       }
+
+       return !dont_verify && mini_method_verify (cfg, method_definition);
+}
+
 static void
 create_helper_signature (void)
 {
@@ -2841,6 +2854,15 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
        return (gpointer)target;
 }
 
+void
+mono_add_seq_point (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins, int native_offset)
+{
+       ins->inst_offset = native_offset;
+       g_ptr_array_add (cfg->seq_points, ins);
+       bb->seq_points = g_slist_prepend_mempool (cfg->mempool, bb->seq_points, ins);
+       bb->last_seq_point = ins;
+}
+
 static void
 mono_compile_create_vars (MonoCompile *cfg)
 {
@@ -3006,6 +3028,93 @@ mono_postprocess_patches (MonoCompile *cfg)
        }
 }
 
+static void
+mono_save_seq_point_info (MonoCompile *cfg)
+{
+       MonoBasicBlock *bb, *in_bb;
+       GSList *bb_seq_points, *l;
+       MonoInst *last;
+       MonoDomain *domain = cfg->domain;
+       int i;
+       MonoSeqPointInfo *info;
+       GSList **next;
+
+       if (!cfg->seq_points)
+               return;
+
+       info = g_malloc0 (sizeof (MonoSeqPointInfo) + (cfg->seq_points->len - MONO_ZERO_LEN_ARRAY) * sizeof (SeqPoint));
+       info->len = cfg->seq_points->len;
+       for (i = 0; i < cfg->seq_points->len; ++i) {
+               SeqPoint *sp = &info->seq_points [i];
+               MonoInst *ins = g_ptr_array_index (cfg->seq_points, i);
+
+               sp->il_offset = ins->inst_imm;
+               sp->native_offset = ins->inst_offset;
+
+               /* Used below */
+               ins->backend.size = i;
+       }
+
+       /*
+        * For each sequence point, compute the list of sequence points immediately
+        * following it, this is needed to implement 'step over' in the debugger agent.
+        */ 
+       next = g_new0 (GSList*, cfg->seq_points->len);
+       for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
+               bb_seq_points = g_slist_reverse (bb->seq_points);
+               last = NULL;
+               for (l = bb_seq_points; l; l = l->next) {
+                       MonoInst *ins = l->data;
+
+                       if (!(ins->flags & MONO_INST_SINGLE_STEP_LOC))
+                               continue;
+
+                       if (last != NULL) {
+                               /* Link with the previous seq point in the same bb */
+                               next [last->backend.size] = g_slist_append (next [last->backend.size], GUINT_TO_POINTER (ins->backend.size));
+                       } else {
+                               /* Link with the last bb in the previous bblocks */
+                               /* 
+                                * FIXME: What if the prev bb doesn't have a seq point, but
+                                * one of its predecessors has ?
+                                */
+                               for (i = 0; i < bb->in_count; ++i) {
+                                       in_bb = bb->in_bb [i];
+
+                                       if (in_bb->last_seq_point)
+                                               next [in_bb->last_seq_point->backend.size] = g_slist_append (next [in_bb->last_seq_point->backend.size], GUINT_TO_POINTER (ins->backend.size));
+                               }
+                       }
+
+                       last = ins;
+               }
+       }
+
+       for (i = 0; i < cfg->seq_points->len; ++i) {
+               SeqPoint *sp = &info->seq_points [i];
+               GSList *l;
+               int j;
+
+               sp->next_len = g_slist_length (next [i]);
+               sp->next = g_new (int, sp->next_len);
+               j = 0;
+               for (l = next [i]; l; l = l->next)
+                       sp->next [j ++] = GPOINTER_TO_UINT (l->data);
+               g_slist_free (next [i]);
+       }
+       g_free (next);
+
+       cfg->seq_point_info = info;
+
+       // FIXME: dynamic methods
+       mono_domain_lock (domain);
+       g_hash_table_insert (domain_jit_info (domain)->seq_points, cfg->method_to_register, info);
+       mono_domain_unlock (domain);
+
+       g_ptr_array_free (cfg->seq_points, TRUE);
+       cfg->seq_points = NULL;
+}
+
 void
 mono_codegen (MonoCompile *cfg)
 {
@@ -3260,6 +3369,9 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        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)) {
                cfg->exception_type = MONO_EXCEPTION_GENERIC_SHARING_FAILED;
                return cfg;
@@ -3275,21 +3387,23 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        }
        cfg->method_to_register = method_to_register;
 
-       /* No way to obtain the location info for 'this' */
-       if (try_generic_shared) {
-               cfg->exception_message = g_strdup ("gshared");
-               cfg->disable_llvm = TRUE;
-       }
+       if (cfg->compile_llvm) {
+               /* No way to obtain the location info for 'this' */
+               if (try_generic_shared) {
+                       cfg->exception_message = g_strdup ("gshared");
+                       cfg->disable_llvm = TRUE;
+               }
 
-       if (cfg->method->save_lmf) {
-               cfg->exception_message = g_strdup ("lmf");
-               cfg->disable_llvm = TRUE;
-       }
+               if (cfg->method->save_lmf) {
+                       cfg->exception_message = g_strdup ("lmf");
+                       cfg->disable_llvm = TRUE;
+               }
 
-       /* FIXME: */
-       if (cfg->method->dynamic) {
-               cfg->exception_message = g_strdup ("dynamic.");
-               cfg->disable_llvm = TRUE;
+               /* FIXME: */
+               if (cfg->method->dynamic) {
+                       cfg->exception_message = g_strdup ("dynamic.");
+                       cfg->disable_llvm = TRUE;
+               }
        }
 
        header = mono_method_get_header (method_to_compile);
@@ -3474,6 +3588,10 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
         */
        //cfg->enable_extended_bblocks = TRUE;
 
+       /*We must verify the method before doing any IR generation as mono_compile_create_vars can assert.*/
+       if (mono_compile_is_broken (cfg))
+               return cfg;
+
        /*
         * create MonoInst* which represents arguments and local variables
         */
@@ -4051,12 +4169,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
 
        mini_gc_create_gc_map (cfg);
  
-       if (cfg->seq_points) {
-               // FIXME: dynamic methods
-               mono_domain_lock (domain);
-               g_hash_table_insert (domain_jit_info (domain)->seq_points, method_to_register, cfg->seq_points);
-               mono_domain_unlock (domain);
-       }
+       mono_save_seq_point_info (cfg);
 
        if (!cfg->compile_aot) {
                mono_domain_lock (cfg->domain);
@@ -4991,6 +5104,8 @@ mini_parse_debug_options (void)
                        debug_options.gdb = TRUE;
                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 = TRUE;
                else {
                        fprintf (stderr, "Invalid option for the MONO_DEBUG env variable: %s\n", arg);
                        fprintf (stderr, "Available options: 'handle-sigint', 'keep-delegates', 'collect-pagefault-stats', 'break-on-unverified', 'no-gdb-backtrace', 'dont-free-domains', 'suspend-on-sigsegv', 'dyn-runtime-invoke', 'gdb', 'explicit-null-checks'\n");
@@ -5057,7 +5172,7 @@ mini_create_jit_domain_info (MonoDomain *domain)
        info->delegate_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
        info->llvm_vcall_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
        info->runtime_invoke_hash = g_hash_table_new_full (mono_aligned_addr_hash, NULL, NULL, runtime_invoke_info_free);
-       info->seq_points = g_hash_table_new (mono_aligned_addr_hash, NULL);
+       info->seq_points = g_hash_table_new_full (mono_aligned_addr_hash, NULL, NULL, g_free);
        info->arch_seq_points = g_hash_table_new (mono_aligned_addr_hash, NULL);
 
        domain->runtime_info = info;
@@ -5116,6 +5231,8 @@ mini_free_jit_domain_info (MonoDomain *domain)
                g_hash_table_destroy (info->static_rgctx_trampoline_hash);
        g_hash_table_destroy (info->llvm_vcall_trampoline_hash);
        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);
@@ -5694,9 +5811,9 @@ char*
 mono_get_runtime_build_info (void)
 {
        if (mono_build_date)
-               return g_strdup_printf ("%s %s", FULL_VERSION, mono_build_date);
+               return g_strdup_printf ("%s (%s %s)", VERSION, FULL_VERSION, mono_build_date);
        else
-               return g_strdup_printf ("%s", FULL_VERSION);
+               return g_strdup_printf ("%s (%s)", VERSION, FULL_VERSION);
 }
 
 static void