2009-01-26 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / mini.c
index 5668458c79970c34b1efc7da0b0eb0b61e270461..03a93ce4c0bbc579bc2108b07670dc58caa68732 100644 (file)
@@ -113,9 +113,6 @@ const char *mono_build_date;
 
 static int mini_verbose = 0;
 
-/* Enable xdebug mode. See aot-compiler.c for documentation */
-static gboolean enable_xdebug = FALSE;
-
 #define mono_jit_lock() EnterCriticalSection (&jit_mutex)
 #define mono_jit_unlock() LeaveCriticalSection (&jit_mutex)
 static CRITICAL_SECTION jit_mutex;
@@ -334,6 +331,24 @@ void *mono_global_codeman_reserve (int size)
        }
 }
 
+/**
+ * mono_create_unwind_op:
+ *
+ *   Create an unwind op with the given parameters.
+ */
+MonoUnwindOp*
+mono_create_unwind_op (int when, int tag, int reg, int val)
+{
+       MonoUnwindOp *op = g_new0 (MonoUnwindOp, 1);
+
+       op->op = tag;
+       op->reg = reg;
+       op->val = val;
+       op->when = when;
+
+       return op;
+}
+
 /**
  * mono_emit_unwind_op:
  *
@@ -667,7 +682,7 @@ mono_op_imm_to_op (int opcode)
 {
        switch (opcode) {
        case OP_ADD_IMM:
-#if SIZEOF_VOID_P == 4
+#if SIZEOF_REGISTER == 4
                return OP_IADD;
 #else
                return OP_LADD;
@@ -683,7 +698,7 @@ mono_op_imm_to_op (int opcode)
        case OP_IMUL_IMM:
                return OP_IMUL;
        case OP_AND_IMM:
-#if SIZEOF_VOID_P == 4
+#if SIZEOF_REGISTER == 4
                return OP_IAND;
 #else
                return OP_LAND;
@@ -721,13 +736,13 @@ mono_op_imm_to_op (int opcode)
        case OP_IREM_IMM:
                return OP_IREM;
        case OP_DIV_IMM:
-#if SIZEOF_VOID_P == 4
+#if SIZEOF_REGISTER == 4
                return OP_IDIV;
 #else
                return OP_LDIV;
 #endif
        case OP_REM_IMM:
-#if SIZEOF_VOID_P == 4
+#if SIZEOF_REGISTER == 4
                return OP_IREM;
 #else
                return OP_LREM;
@@ -832,7 +847,7 @@ mono_compile_create_var_for_vreg (MonoCompile *cfg, MonoType *type, int opcode,
        if (vreg != -1)
                set_vreg_to_inst (cfg, vreg, inst);
 
-#if SIZEOF_VOID_P == 4
+#if SIZEOF_REGISTER == 4
 #ifdef MONO_ARCH_SOFT_FLOAT
        regpair = mono_type_is_long (type) || mono_type_is_float (type);
 #else
@@ -1365,8 +1380,9 @@ mono_allocate_stack_slots_full2 (MonoCompile *cfg, gboolean backward, guint32 *s
 
                /* 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 (inst->inst_vtype->data.klass, &align);
+               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);
+               }
                else {
                        int ialign;
 
@@ -1405,7 +1421,7 @@ mono_allocate_stack_slots_full2 (MonoCompile *cfg, gboolean backward, guint32 *s
                case MONO_TYPE_PTR:
                case MONO_TYPE_I:
                case MONO_TYPE_U:
-#if SIZEOF_VOID_P == 4
+#if SIZEOF_REGISTER == 4
                case MONO_TYPE_I4:
 #else
                case MONO_TYPE_I8:
@@ -1626,9 +1642,9 @@ mono_allocate_stack_slots_full (MonoCompile *cfg, gboolean backward, guint32 *st
 
                /* 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 (inst->inst_vtype->data.klass, &align);
-               else {
+               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);
+               else {
                        int ialign;
 
                        size = mono_type_size (inst->inst_vtype, &ialign);
@@ -1669,7 +1685,7 @@ mono_allocate_stack_slots_full (MonoCompile *cfg, gboolean backward, guint32 *st
                        case MONO_TYPE_PTR:
                        case MONO_TYPE_I:
                        case MONO_TYPE_U:
-#if SIZEOF_VOID_P == 4
+#if SIZEOF_REGISTER == 4
                        case MONO_TYPE_I4:
 #else
                        case MONO_TYPE_I8:
@@ -2215,7 +2231,24 @@ mini_thread_cleanup (MonoThread *thread)
                g_free (jit_tls->first_lmf);
                g_free (jit_tls);
                thread->jit_data = NULL;
-               TlsSetValue (mono_jit_tls_id, NULL);
+
+               /* 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_current ()) {
+                       TlsSetValue (mono_jit_tls_id, NULL);
+
+#ifdef HAVE_KW_THREAD
+                       mono_jit_tls = NULL;
+                       mono_lmf_addr = NULL;
+#if defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
+                       mono_lmf = NULL;
+#endif
+#endif         
+               }
        }
 }
 
@@ -2243,6 +2276,18 @@ mono_get_jit_tls_intrinsic (MonoCompile *cfg)
        return mono_create_tls_get (cfg, mono_get_jit_tls_offset ());
 }
 
+MonoInst*
+mono_get_domain_intrinsic (MonoCompile* cfg)
+{
+       return mono_create_tls_get (cfg, mono_domain_get_tls_offset ());
+}
+
+MonoInst*
+mono_get_thread_intrinsic (MonoCompile* cfg)
+{
+       return mono_create_tls_get (cfg, mono_thread_get_tls_offset ());
+}
+
 void
 mono_add_patch_info (MonoCompile *cfg, int ip, MonoJumpInfoType type, gconstpointer target)
 {
@@ -2953,6 +2998,34 @@ compute_reachable (MonoBasicBlock *bb)
        }
 }
 
+static MonoGenericContext
+construct_object_context_for_method (MonoMethod *method)
+{
+       MonoGenericContext object_context;
+
+       g_assert (method->wrapper_type == MONO_WRAPPER_NONE);
+       g_assert (!method->klass->generic_class);
+       if (method->klass->generic_container) {
+               int type_argc = method->klass->generic_container->type_argc;
+
+               object_context.class_inst = get_object_generic_inst (type_argc);
+       } else {
+               object_context.class_inst = NULL;
+       }
+
+       if (mini_method_get_context (method)->method_inst) {
+               int type_argc = mini_method_get_context (method)->method_inst->type_argc;
+
+               object_context.method_inst = get_object_generic_inst (type_argc);
+       } else {
+               object_context.method_inst = NULL;
+       }
+
+       g_assert (object_context.class_inst || object_context.method_inst);
+
+       return object_context;
+}
+
 /*
  * mini_method_compile:
  * @method: the method to compile
@@ -3062,6 +3135,10 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
                /* The debugger needs all locals to be on the stack or in a global register */
                cfg->disable_vreg_to_lvreg = TRUE;
 
+               /* Don't remove unused variables when running inside the debugger since the user
+                * may still want to view them. */
+               cfg->disable_deadce_vars = TRUE;
+
                // cfg->opt |= MONO_OPT_SHARED;
                cfg->opt &= ~MONO_OPT_DEADCE;
                cfg->opt &= ~MONO_OPT_INLINE;
@@ -3511,26 +3588,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        }
 
        if (cfg->generic_sharing_context) {
-               MonoGenericContext object_context;
-
-               g_assert (!method_to_compile->klass->generic_class);
-               if (method_to_compile->klass->generic_container) {
-                       int type_argc = method_to_compile->klass->generic_container->type_argc;
-
-                       object_context.class_inst = get_object_generic_inst (type_argc);
-               } else {
-                       object_context.class_inst = NULL;
-               }
-
-               if (mini_method_get_context (method_to_compile)->method_inst) {
-                       int type_argc = mini_method_get_context (method_to_compile)->method_inst->type_argc;
-
-                       object_context.method_inst = get_object_generic_inst (type_argc);
-               } else {
-                       object_context.method_inst = NULL;
-               }
-
-               g_assert (object_context.class_inst || object_context.method_inst);
+               MonoGenericContext object_context = construct_object_context_for_method (method_to_compile);
 
                method_to_register = mono_class_inflate_generic_method (method_to_compile, &object_context);
        } else {
@@ -3638,16 +3696,20 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
                }
        }
 
+       if (cfg->unwind_ops) {
+               guint32 info_len;
+               guint8 *unwind_info = mono_unwind_ops_encode (cfg->unwind_ops, &info_len);
+
+               jinfo->used_regs = mono_cache_unwind_info (unwind_info, info_len);
+               g_free (unwind_info);
+       }
+
        cfg->jit_info = jinfo;
 #if defined(__arm__)
        mono_arch_fixup_jinfo (cfg);
 #endif
 
-       if (enable_xdebug) {
-#ifndef DISABLE_AOT
-               mono_save_xdebug_info (method_to_register, jinfo->code_start, jinfo->code_size, cfg->args, cfg->unwind_ops);
-#endif
-       }
+       mono_save_xdebug_info (method_to_register, jinfo->code_start, jinfo->code_size, cfg->args, cfg->unwind_ops);
 
        if (!cfg->compile_aot) {
                mono_domain_lock (cfg->domain);
@@ -3695,6 +3757,37 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
 
 #endif /* DISABLE_JIT */
 
+MonoJitInfo*
+mono_domain_lookup_shared_generic (MonoDomain *domain, MonoMethod *open_method)
+{
+       static gboolean inited = FALSE;
+       static int lookups = 0;
+       static int failed_lookups = 0;
+
+       MonoGenericContext object_context;
+       MonoMethod *object_method;
+       MonoJitInfo *ji;
+
+       object_context = construct_object_context_for_method (open_method);
+       object_method = mono_class_inflate_generic_method (open_method, &object_context);
+
+       ji = mono_internal_hash_table_lookup (&domain->jit_code_hash, object_method);
+       if (ji && !ji->has_generic_jit_info)
+               ji = NULL;
+
+       if (!inited) {
+               mono_counters_register ("Shared generic lookups", MONO_COUNTER_INT|MONO_COUNTER_GENERICS, &lookups);
+               mono_counters_register ("Failed shared generic lookups", MONO_COUNTER_INT|MONO_COUNTER_GENERICS, &failed_lookups);
+               inited = TRUE;
+       }
+
+       ++lookups;
+       if (!ji)
+               ++failed_lookups;
+
+       return ji;
+}
+
 static MonoJitInfo*
 lookup_generic_method (MonoDomain *domain, MonoMethod *method)
 {
@@ -3703,7 +3796,7 @@ lookup_generic_method (MonoDomain *domain, MonoMethod *method)
        if (!mono_method_is_generic_sharable_impl (method, FALSE))
                return NULL;
 
-       open_method = mono_method_get_declaring_generic_method (method);
+       open_method = mono_method_get_declaring_generic_method (method);
 
        return mono_domain_lookup_shared_generic (domain, open_method);
 }
@@ -3748,16 +3841,12 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
 
                mono_class_init (method->klass);
 
-               mono_domain_lock (domain);
                if ((code = mono_aot_get_method (domain, method))) {
-                       mono_domain_unlock (domain);
                        vtable = mono_class_vtable (domain, method->klass);
                        g_assert (vtable);
                        mono_runtime_class_init (vtable);
                        return code;
                }
-
-               mono_domain_unlock (domain);
        }
 #endif
 
@@ -3932,12 +4021,8 @@ 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)) {
-                       /* g_print ("inserting method %s.%s.%s\n", method->klass->name_space, method->klass->name, method->name); */
-                       mono_domain_register_shared_generic (target_domain, 
-                               mono_method_get_declaring_generic_method (method), cfg->jit_info);
+               if (cfg->generic_sharing_context && mono_method_is_generic_sharable_impl (method, FALSE))
                        mono_stats.generics_shared_methods++;
-               }
        } else {
                mono_domain_jit_code_hash_unlock (target_domain);
        }
@@ -4301,10 +4386,16 @@ SIG_HANDLER_SIGNATURE (sigusr1_signal_handler)
        gboolean running_managed;
        MonoException *exc;
        MonoThread *thread = mono_thread_current ();
+       MonoDomain *domain = mono_domain_get ();
        void *ji;
        
        GET_CONTEXT;
 
+       if (!thread || !domain)
+               /* The thread might not have started up yet */
+               /* FIXME: Specify the synchronization with start_wrapper () in threads.c */
+               return;
+
        if (thread->thread_dump_requested) {
                thread->thread_dump_requested = FALSE;
 
@@ -4990,6 +5081,14 @@ mini_init (const char *filename, const char *runtime_version)
 
        mono_arch_init ();
 
+       mono_unwind_init ();
+
+       if (getenv ("MONO_XDEBUG")) {
+               mono_xdebug_init ();
+               /* So methods for multiple domains don't have the same address */
+               mono_dont_free_domains = TRUE;
+       }
+
        mono_trampolines_init ();
 
        if (!g_thread_supported ())
@@ -5019,9 +5118,6 @@ mini_init (const char *filename, const char *runtime_version)
        }
 #endif
 
-       if (getenv ("MONO_XDEBUG"))
-               enable_xdebug = TRUE;
-
 #define JIT_TRAMPOLINES_WORK
 #ifdef JIT_TRAMPOLINES_WORK
        mono_install_compile_method (mono_jit_compile_method);
@@ -5220,7 +5316,7 @@ mini_init (const char *filename, const char *runtime_version)
        register_icall (mono_fload_r4_arg, "mono_fload_r4_arg", "uint32 double", FALSE);
 #endif
 
-#if SIZEOF_VOID_P == 4
+#if SIZEOF_REGISTER == 4
        mono_register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", "uint32 double", mono_fconv_u4, TRUE);
 #endif
 
@@ -5409,6 +5505,8 @@ mini_cleanup (MonoDomain *domain)
 
        mono_trampolines_cleanup ();
 
+       mono_unwind_cleanup ();
+
        if (!mono_dont_free_global_codeman)
                mono_code_manager_destroy (global_codeman);
        g_hash_table_destroy (jit_icall_name_hash);