2009-07-30 Mark Probst <mark.probst@gmail.com>
[mono.git] / mono / mini / mini.c
index 039fe06bbef8ecf15fd911f2a3268d169468137b..252fc9f68248231bc8988a427a64d221ecc5ccd2 100644 (file)
@@ -66,8 +66,7 @@
 #include "debug-mini.h"
 #include "mini-gc.h"
 
-static gpointer mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt);
-static gpointer mono_jit_compile_method (MonoMethod *method);
+static gpointer mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, MonoException **ex);
 
 /* helper methods signature */
 /* FIXME: Make these static again */
@@ -2173,6 +2172,13 @@ mono_get_lmf_addr (void)
 void
 mono_jit_thread_attach (MonoDomain *domain)
 {
+       if (!domain)
+               /* 
+                * Happens when called from AOTed code which is only used in the root
+                * domain.
+                */
+               domain = mono_get_root_domain ();
+
 #ifdef HAVE_KW_THREAD
        if (!mono_lmf_addr) {
                mono_thread_attach (domain);
@@ -2261,7 +2267,7 @@ mono_thread_start_cb (gsize tid, gpointer stack_start, gpointer func)
        MonoThread *thread;
        void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort);
        thread = mono_thread_current ();
-       mono_debugger_thread_created (tid, thread, jit_tls);
+       mono_debugger_thread_created (tid, thread, jit_tls, func);
        if (thread)
                thread->jit_data = jit_tls;
 }
@@ -2283,7 +2289,7 @@ mono_thread_attach_cb (gsize tid, gpointer stack_start)
        MonoThread *thread;
        void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort_dummy);
        thread = mono_thread_current ();
-       mono_debugger_thread_created (tid, thread, (MonoJitTlsData *) jit_tls);
+       mono_debugger_thread_created (tid, thread, (MonoJitTlsData *) jit_tls, NULL);
        if (thread)
                thread->jit_data = jit_tls;
        if (mono_profiler_get_events () & MONO_PROFILE_STATISTICAL)
@@ -2449,6 +2455,8 @@ mono_patch_info_hash (gconstpointer data)
        case MONO_PATCH_INFO_LDTOKEN:
        case MONO_PATCH_INFO_DECLSEC:
                return (ji->type << 8) | ji->data.token->token;
+       case MONO_PATCH_INFO_INTERNAL_METHOD:
+               return (ji->type << 8) | g_str_hash (ji->data.name);
        case MONO_PATCH_INFO_VTABLE:
        case MONO_PATCH_INFO_CLASS:
        case MONO_PATCH_INFO_IID:
@@ -2458,7 +2466,6 @@ mono_patch_info_hash (gconstpointer data)
        case MONO_PATCH_INFO_METHOD:
        case MONO_PATCH_INFO_METHOD_JUMP:
        case MONO_PATCH_INFO_IMAGE:
-       case MONO_PATCH_INFO_INTERNAL_METHOD:
        case MONO_PATCH_INFO_JIT_ICALL_ADDR:
        case MONO_PATCH_INFO_FIELD:
        case MONO_PATCH_INFO_SFLDA:
@@ -2497,6 +2504,16 @@ mono_patch_info_equal (gconstpointer ka, gconstpointer kb)
                        (ji1->data.token->context.method_inst != ji2->data.token->context.method_inst))
                        return 0;
                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);
+       }
+
        default:
                if (ji1->data.target != ji2->data.target)
                        return 0;
@@ -2546,12 +2563,7 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
                        target = code;
                } else {
                        /* get the trampoline to the method from the domain */
-                       if (method && method->wrapper_type == MONO_WRAPPER_STATIC_RGCTX_INVOKE) {
-                               target = mono_create_jit_trampoline_in_domain (mono_domain_get (),
-                                       patch_info->data.method);
-                       } else {
-                               target = mono_create_jit_trampoline (patch_info->data.method);
-                       }
+                       target = mono_create_jit_trampoline (patch_info->data.method);
                }
                break;
        case MONO_PATCH_INFO_SWITCH: {
@@ -3038,6 +3050,7 @@ if (valgrind_register){
        } else {
                mono_domain_code_commit (cfg->domain, cfg->native_code, cfg->code_size, cfg->code_len);
        }
+       mono_profiler_code_buffer_new (code, cfg->code_len, MONO_PROFILER_CODE_BUFFER_METHOD, cfg->method);
        
        mono_arch_flush_icache (cfg->native_code, cfg->code_len);
 
@@ -3960,12 +3973,13 @@ lookup_method (MonoDomain *domain, MonoMethod *method)
 }
 
 static gpointer
-mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, int opt)
+mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, int opt, MonoException **jit_ex)
 {
        MonoCompile *cfg;
        gpointer code = NULL;
        MonoJitInfo *info;
        MonoVTable *vtable;
+       MonoException *ex = NULL;
 
 #ifdef MONO_USE_AOT_COMPILER
        if ((opt & MONO_OPT_AOT) && !(mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION)) {
@@ -4056,7 +4070,6 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
        case MONO_EXCEPTION_BAD_IMAGE: {
                /* Throw a type load exception if needed */
                MonoLoaderError *error = mono_loader_get_last_error ();
-               MonoException *ex;
 
                if (error) {
                        ex = mono_loader_error_prepare_exception (error);
@@ -4078,34 +4091,20 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
                                        g_assert_not_reached ();
                        }
                }
-               mono_destroy_compile (cfg);
-               mono_raise_exception (ex);
                break;
        }
-       case MONO_EXCEPTION_INVALID_PROGRAM: {
-               MonoException *ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "InvalidProgramException", cfg->exception_message);
-               mono_destroy_compile (cfg);
-               mono_raise_exception (ex);
+       case MONO_EXCEPTION_INVALID_PROGRAM:
+               ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "InvalidProgramException", cfg->exception_message);
                break;
-       }
-       case MONO_EXCEPTION_UNVERIFIABLE_IL: {
-               MonoException *ex = mono_exception_from_name_msg (mono_defaults.corlib, "System.Security", "VerificationException", cfg->exception_message);
-               mono_destroy_compile (cfg);
-               mono_raise_exception (ex);
+       case MONO_EXCEPTION_UNVERIFIABLE_IL:
+               ex = mono_exception_from_name_msg (mono_defaults.corlib, "System.Security", "VerificationException", cfg->exception_message);
                break;
-       }
-       case MONO_EXCEPTION_METHOD_ACCESS: {
-               MonoException *ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "MethodAccessException", cfg->exception_message);
-               mono_destroy_compile (cfg);
-               mono_raise_exception (ex);
+       case MONO_EXCEPTION_METHOD_ACCESS:
+               ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "MethodAccessException", cfg->exception_message);
                break;
-       }
-       case MONO_EXCEPTION_FIELD_ACCESS: {
-               MonoException *ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "FieldAccessException", cfg->exception_message);
-               mono_destroy_compile (cfg);
-               mono_raise_exception (ex);
+       case MONO_EXCEPTION_FIELD_ACCESS:
+               ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "FieldAccessException", cfg->exception_message);
                break;
-       }
        /* this can only be set if the security manager is active */
        case MONO_EXCEPTION_SECURITY_LINKDEMAND: {
                MonoSecurityManager* secman = mono_security_manager_get_methods ();
@@ -4116,22 +4115,26 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
                args [1] = &method;
                mono_runtime_invoke (secman->linkdemandsecurityexception, NULL, args, &exc);
 
-               mono_destroy_compile (cfg);
-               cfg = NULL;
-
-               mono_raise_exception ((MonoException*)exc);
+               ex = (MonoException*)exc;
+               break;
        }
        case MONO_EXCEPTION_OBJECT_SUPPLIED: {
                MonoException *exp = cfg->exception_ptr;
                MONO_GC_UNREGISTER_ROOT (cfg->exception_ptr);
-               mono_destroy_compile (cfg);
-               mono_raise_exception (exp);
+
+               ex = exp;
                break;
        }
        default:
                g_assert_not_reached ();
        }
 
+       if (ex) {
+               mono_destroy_compile (cfg);
+               *jit_ex = ex;
+               return NULL;
+       }
+
        mono_loader_lock (); /*FIXME lookup_method_inner requires the loader lock*/
        mono_domain_lock (target_domain);
 
@@ -4193,11 +4196,11 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
 }
 
 static gpointer
-mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt)
+mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, MonoException **ex)
 {
        MonoDomain *target_domain, *domain = mono_domain_get ();
        MonoJitInfo *info;
-       gpointer p;
+       gpointer code, p;
        MonoJitICallInfo *callinfo = NULL;
 
        /*
@@ -4234,7 +4237,11 @@ mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt)
                }
        }
 
-       p = mono_create_ftnptr (target_domain, mono_jit_compile_method_inner (method, target_domain, opt));
+       code = mono_jit_compile_method_inner (method, target_domain, opt, ex);
+       if (!code)
+               return NULL;
+
+       p = mono_create_ftnptr (target_domain, code);
 
        if (callinfo) {
                mono_jit_lock ();
@@ -4249,10 +4256,19 @@ mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt)
        return p;
 }
 
-static gpointer
+gpointer
 mono_jit_compile_method (MonoMethod *method)
 {
-       return mono_jit_compile_method_with_opt (method, default_opt);
+       MonoException *ex = NULL;
+       gpointer code;
+
+       code = mono_jit_compile_method_with_opt (method, default_opt, &ex);
+       if (!code) {
+               g_assert (ex);
+               mono_raise_exception (ex);
+       }
+
+       return code;
 }
 
 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
@@ -4288,6 +4304,7 @@ mono_jit_free_method (MonoDomain *domain, MonoMethod *method)
        g_hash_table_remove (domain_jit_info (domain)->dynamic_code_hash, method);
        mono_internal_hash_table_remove (&domain->jit_code_hash, method);
        g_hash_table_remove (domain_jit_info (domain)->jump_trampoline_hash, method);
+       g_hash_table_remove (domain_jit_info (domain)->runtime_invoke_hash, method);
        mono_domain_unlock (domain);
 
 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
@@ -4350,6 +4367,13 @@ mono_jit_find_compiled_method (MonoDomain *domain, MonoMethod *method)
        return mono_jit_find_compiled_method_with_jit_info (domain, method, NULL);
 }
 
+typedef struct {
+       MonoMethod *method;
+       gpointer compiled_method;
+       gpointer runtime_invoke;
+       MonoVTable *vtable;
+} RuntimeInvokeInfo;
+
 /**
  * mono_jit_runtime_invoke:
  * @method: the method to invoke
@@ -4360,60 +4384,77 @@ mono_jit_find_compiled_method (MonoDomain *domain, MonoMethod *method)
 static MonoObject*
 mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
 {
-       MonoMethod *to_compile;
        MonoMethod *invoke;
        MonoObject *(*runtime_invoke) (MonoObject *this, void **params, MonoObject **exc, void* compiled_method);
-       void* compiled_method;
-       MonoVTable *vtable;
-       gboolean need_rgctx_tramp = FALSE;
-
+       MonoDomain *domain = mono_domain_get ();
+       MonoJitDomainInfo *domain_info;
+       RuntimeInvokeInfo *info, *info2;
+       
        if (obj == NULL && !(method->flags & METHOD_ATTRIBUTE_STATIC) && !method->string_ctor && (method->wrapper_type == 0)) {
                g_warning ("Ignoring invocation of an instance method on a NULL instance.\n");
                return NULL;
        }
 
-       to_compile = method;
+       domain_info = domain_jit_info (domain);
 
-       if (mono_method_needs_static_rgctx_invoke (method, FALSE))
-               need_rgctx_tramp = TRUE;
+       mono_domain_lock (domain);
+       info = g_hash_table_lookup (domain_info->runtime_invoke_hash, method);
+       mono_domain_unlock (domain);            
 
-       /* Special case parameterless ctors to speed up Activator.CreateInstance () */
-       if (method->flags & (METHOD_ATTRIBUTE_SPECIAL_NAME | METHOD_ATTRIBUTE_RT_SPECIAL_NAME) && !strcmp (method->name, ".ctor") && mono_method_signature (method)->param_count == 0 && !method->klass->valuetype) {
-               MonoJitDomainInfo *domain_info = domain_jit_info (mono_domain_get ());
+       if (!info) {
+               info = g_new0 (RuntimeInvokeInfo, 1);
 
-               if (!domain_info->ctor_runtime_invoke) {
-                       invoke = mono_marshal_get_runtime_invoke (method, FALSE);
-                       domain_info->ctor_runtime_invoke = mono_jit_compile_method (invoke);
+               invoke = mono_marshal_get_runtime_invoke (method, FALSE);
+               info->runtime_invoke = mono_jit_compile_method (invoke);
+               info->vtable = mono_class_vtable (domain, method->klass);
+               g_assert (info->vtable);
+
+               if (method->klass->rank && (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
+                       (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)) {
+                       /* 
+                        * Array Get/Set/Address methods. The JIT implements them using inline code 
+                        * inside the runtime invoke wrappers, so no need to compile them.
+                        */
+                       info->compiled_method = NULL;
+               } else {
+                       MonoException *jit_ex = NULL;
+
+                       info->compiled_method = mono_jit_compile_method_with_opt (method, default_opt, &jit_ex);
+                       if (!info->compiled_method) {
+                               g_free (info);
+                               g_assert (jit_ex);
+                               if (exc) {
+                                       *exc = (MonoObject*)jit_ex;
+                                       return NULL;
+                               } else {
+                                       mono_raise_exception (jit_ex);
+                               }
+                       }
+
+                       if (mono_method_needs_static_rgctx_invoke (method, FALSE))
+                               info->compiled_method = mono_create_static_rgctx_trampoline (method, info->compiled_method);
                }
 
-               runtime_invoke = domain_info->ctor_runtime_invoke;
-       } else {
-               invoke = mono_marshal_get_runtime_invoke (method, FALSE);
-               runtime_invoke = mono_jit_compile_method (invoke);
+               mono_domain_lock (domain);
+               info2 = g_hash_table_lookup (domain_info->runtime_invoke_hash, method);
+               if (info2) {
+                       g_free (info);
+                       info = info2;
+               } else {
+                       g_hash_table_insert (domain_info->runtime_invoke_hash, method, info);
+               }
+               mono_domain_unlock (domain);            
        }
 
+       runtime_invoke = info->runtime_invoke;
+
        /*
         * We need this here because mono_marshal_get_runtime_invoke can place 
         * the helper method in System.Object and not the target class.
         */
-       vtable = mono_class_vtable (mono_domain_get (), method->klass);
-       g_assert (vtable);
-       mono_runtime_class_init (vtable);
+       mono_runtime_class_init (info->vtable);
 
-       if (method->klass->rank && (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
-               (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)) {
-               /* 
-                * Array Get/Set/Address methods. The JIT implements them using inline code 
-                * inside the runtime invoke wrappers, so no need to compile them.
-                */
-               compiled_method = NULL;
-       } else {
-               compiled_method = mono_jit_compile_method (to_compile);
-       }
-       if (need_rgctx_tramp)
-               compiled_method = mono_create_static_rgctx_trampoline (to_compile, compiled_method);
-
-       return runtime_invoke (obj, params, exc, compiled_method);
+       return runtime_invoke (obj, params, exc, info->compiled_method);
 }
 
 void
@@ -4619,6 +4660,43 @@ mini_get_debug_options (void)
 {
        return &debug_options;
 }
+
+static gpointer
+mini_create_ftnptr (MonoDomain *domain, gpointer addr)
+{
+#ifdef __ia64__
+       gpointer *desc;
+
+       desc = mono_domain_code_reserve (domain, 2 * sizeof (gpointer));
+
+       desc [0] = addr;
+       desc [1] = NULL;
+
+       return desc;
+#elif defined(__ppc64__) || defined(__powerpc64__)
+       gpointer *desc;
+
+       desc = mono_domain_alloc0 (domain, 3 * sizeof (gpointer));
+
+       desc [0] = addr;
+       desc [1] = NULL;
+       desc [2] = NULL;
+
+       return desc;
+#else
+       return addr;
+#endif
+}
+
+static gpointer
+mini_get_addr_from_ftnptr (gpointer descr)
+{
+#if defined(__ia64__) || defined(__ppc64__) || defined(__powerpc64__)
+       return *(gpointer*)descr;
+#else
+       return descr;
+#endif
+}      
  
 static void
 mini_create_jit_domain_info (MonoDomain *domain)
@@ -4631,6 +4709,7 @@ mini_create_jit_domain_info (MonoDomain *domain)
        info->delegate_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
        info->static_rgctx_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, g_free);
 
        domain->runtime_info = info;
 }
@@ -4674,6 +4753,7 @@ mini_free_jit_domain_info (MonoDomain *domain)
        g_hash_table_destroy (info->delegate_trampoline_hash);
        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_free (domain->runtime_info);
        domain->runtime_info = NULL;
@@ -4683,6 +4763,7 @@ MonoDomain *
 mini_init (const char *filename, const char *runtime_version)
 {
        MonoDomain *domain;
+       MonoRuntimeCallbacks callbacks;
 
        MONO_PROBE_VES_INIT_BEGIN ();
 
@@ -4699,10 +4780,27 @@ mini_init (const char *filename, const char *runtime_version)
 
        InitializeCriticalSection (&jit_mutex);
 
+#ifdef MONO_DEBUGGER_SUPPORTED
+       if (mini_debug_running_inside_mdb ())
+               mini_debugger_init ();
+#endif
+
+#ifdef MONO_ARCH_HAVE_TLS_GET
+       mono_runtime_set_has_tls_get (TRUE);
+#else
+       mono_runtime_set_has_tls_get (FALSE);
+#endif
+
        if (!global_codeman)
                global_codeman = mono_code_manager_new ();
        jit_icall_name_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
 
+       memset (&callbacks, 0, sizeof (callbacks));
+       callbacks.create_ftnptr = mini_create_ftnptr;
+       callbacks.get_addr_from_ftnptr = mini_get_addr_from_ftnptr;
+
+       mono_install_callbacks (&callbacks);
+       
        mono_arch_cpu_init ();
 
        mono_arch_init ();
@@ -4742,7 +4840,9 @@ mini_init (const char *filename, const char *runtime_version)
        mono_set_generic_sharing_supported (TRUE);
 #endif
 
+#ifndef MONO_CROSS_COMPILE
        mono_runtime_install_handlers ();
+#endif
        mono_threads_install_cleanup (mini_thread_cleanup);
 
 #ifdef MONO_ARCH_HAVE_NOTIFY_PENDING_EXC
@@ -5130,7 +5230,8 @@ mini_cleanup (MonoDomain *domain)
 #ifndef DISABLE_COM
        cominterop_release_all_rcws ();
 #endif
-       
+
+#ifndef MONO_CROSS_COMPILE     
        /* 
         * mono_runtime_cleanup() and mono_domain_finalize () need to
         * be called early since they need the execution engine still
@@ -5138,11 +5239,14 @@ mini_cleanup (MonoDomain *domain)
         * and mono_runtime_cleanup will wait for other threads to finish).
         */
        mono_domain_finalize (domain, 2000);
+#endif
 
        /* This accesses metadata so needs to be called before runtime shutdown */
        print_jit_stats ();
 
+#ifndef MONO_CROSS_COMPILE
        mono_runtime_cleanup (domain);
+#endif
 
        mono_profiler_shutdown ();