2010-02-13 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / aot-runtime.c
index 3d74dd0a839be0adbfcf5f72e056120dd9ff8995..7f02b7593c66057a462593390cbf3ab581b6a34f 100644 (file)
@@ -162,6 +162,7 @@ static gint32 mono_last_aot_method = -1;
 
 static gboolean make_unreadable = FALSE;
 static guint32 name_table_accesses = 0;
+static guint32 n_pagefaults = 0;
 
 /* Used to speed-up find_aot_module () */
 static gsize aot_code_low_addr = (gssize)-1;
@@ -586,6 +587,9 @@ decode_method_ref (MonoAotModule *module, guint32 *token, MonoMethod **method, g
                        *method = mono_gc_get_managed_allocator_by_type (atype);
                        break;
                }
+               case MONO_WRAPPER_WRITE_BARRIER:
+                       *method = mono_gc_get_write_barrier ();
+                       break;
                case MONO_WRAPPER_STELEMREF:
                        *method = mono_marshal_get_stelemref ();
                        break;
@@ -623,6 +627,19 @@ decode_method_ref (MonoAotModule *module, guint32 *token, MonoMethod **method, g
                        *method = mono_marshal_get_runtime_invoke (m, FALSE);
                        break;
                }
+               case MONO_WRAPPER_MANAGED_TO_MANAGED: {
+                       int subtype = decode_value (p, &p);
+
+                       if (subtype == MONO_AOT_WRAPPER_ELEMENT_ADDR) {
+                               int rank = decode_value (p, &p);
+                               int elem_size = decode_value (p, &p);
+
+                               *method = mono_marshal_get_array_address (rank, elem_size);
+                       } else {
+                               g_assert_not_reached ();
+                       }
+                       break;
+               }
                default:
                        g_assert_not_reached ();
                }
@@ -895,7 +912,7 @@ find_symbol (MonoDl *module, gpointer *globals, const char *name, gpointer *valu
                table_size = table [0];
                table ++;
 
-               hash = mono_aot_str_hash (name) % table_size;
+               hash = mono_metadata_str_hash (name) % table_size;
 
                entry = &table [hash * 2];
 
@@ -1159,17 +1176,19 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data)
        if (make_unreadable) {
 #ifndef TARGET_WIN32
                guint8 *addr;
-               guint8 *page_start;
-               int pages, err, len;
+               guint8 *page_start, *page_end;
+               int err, len;
 
                addr = amodule->mem_begin;
                len = amodule->mem_end - amodule->mem_begin;
 
                /* Round down in both directions to avoid modifying data which is not ours */
                page_start = (guint8 *) (((gssize) (addr)) & ~ (mono_pagesize () - 1)) + mono_pagesize ();
-               pages = ((addr + len - page_start + mono_pagesize () - 1) / mono_pagesize ()) - 1;
-               err = mono_mprotect (page_start, pages * mono_pagesize (), MONO_MMAP_NONE);
-               g_assert (err == 0);
+               page_end = (guint8 *) (((gssize) (addr + len)) & ~ (mono_pagesize () - 1));
+               if (page_end > page_start) {
+                       err = mono_mprotect (page_start, (page_end - page_start), MONO_MMAP_NONE);
+                       g_assert (err == 0);
+               }
 #endif
        }
 
@@ -1435,7 +1454,7 @@ mono_aot_get_class_from_name (MonoImage *image, const char *name_space, const ch
                        full_name = g_strdup_printf ("%s.%s", name_space, name);
                }
        }
-       hash = mono_aot_str_hash (full_name) % table_size;
+       hash = mono_metadata_str_hash (full_name) % table_size;
        if (full_name != full_name_buf)
                g_free (full_name);
 
@@ -1984,6 +2003,7 @@ decode_exception_debug_info (MonoAotModule *amodule, MonoDomain *domain,
                int len = decode_value (p, &p);
 
                seq_points = g_malloc0 (sizeof (MonoSeqPointInfo) + (len - MONO_ZERO_LEN_ARRAY) * sizeof (SeqPoint));
+               seq_points->len = len;
                last_il_offset = last_native_offset = 0;
                for (i = 0; i < len; ++i) {
                        SeqPoint *sp = &seq_points->seq_points [i];
@@ -2507,10 +2527,15 @@ load_method (MonoDomain *domain, MonoAotModule *amodule, MonoImage *image, MonoM
                if (mono_jit_stats.methods_aot >= mono_last_aot_method)
                                return NULL;
                else if (mono_jit_stats.methods_aot == mono_last_aot_method - 1) {
-                       if (method)
-                               printf ("LAST AOT METHOD: %s%s%s.%s.\n", method->klass->name_space, method->klass->name_space [0] ? "." : "", method->klass->name, method->name);
-                       else
+                       if (!method)
+                               method = mono_get_method (image, token, NULL);
+                       if (method) {
+                               char *name = mono_method_full_name (method, TRUE);
+                               printf ("LAST AOT METHOD: %s.\n", name);
+                               g_free (name);
+                       } else {
                                printf ("LAST AOT METHOD: %p %d\n", code, method_index);
+                       }
                }
        }
 
@@ -2841,8 +2866,11 @@ mono_aot_get_method (MonoDomain *domain, MonoMethod *method)
 
                        code = mono_aot_get_method (domain, m);
                        if (code) {
-                               if (mono_method_needs_static_rgctx_invoke (m, FALSE))
-                                       code = mono_create_static_rgctx_trampoline (m, code);
+                               if (mono_method_needs_static_rgctx_invoke (m, FALSE)) {
+                                       code = mono_create_static_rgctx_trampoline (m, mono_create_ftnptr (domain, code));
+                                       /* The call above returns an ftnptr */
+                                       code = mono_get_addr_from_ftnptr (code);
+                               }
 
                                return code;
                        }
@@ -3048,6 +3076,11 @@ mono_aot_plt_resolve (gpointer aot_module, guint32 plt_info_offset, guint8 *code
         */
        if (ji.type == MONO_PATCH_INFO_ABS || ji.type == MONO_PATCH_INFO_INTERNAL_METHOD || ji.type == MONO_PATCH_INFO_CLASS_INIT || ji.type == MONO_PATCH_INFO_ICALL_ADDR || ji.type == MONO_PATCH_INFO_JIT_ICALL_ADDR || ji.type == MONO_PATCH_INFO_RGCTX_FETCH) {
                /* These should already have a function descriptor */
+#ifdef PPC_USES_FUNCTION_DESCRIPTOR
+               /* Our function descriptors have a 0 environment, gcc created ones don't */
+               if (ji.type != MONO_PATCH_INFO_INTERNAL_METHOD && ji.type != MONO_PATCH_INFO_JIT_ICALL_ADDR && ji.type != MONO_PATCH_INFO_ICALL_ADDR)
+                       g_assert (((gpointer*)target) [2] == 0);
+#endif
                /* Empty */
        } else if (!no_ftnptr) {
 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
@@ -3510,7 +3543,8 @@ mono_aot_get_lazy_fetch_trampoline (guint32 slot)
        symbol = g_strdup_printf ("rgctx_fetch_trampoline_%u", slot);
        code = load_function (mono_defaults.corlib->aot_module, symbol);
        g_free (symbol);
-       return code;
+       /* The caller expects an ftnptr */
+       return mono_create_ftnptr (mono_domain_get (), code);
 }
 
 gpointer
@@ -3543,6 +3577,98 @@ mono_aot_get_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem
 
        return code;
 }
+/*
+ * mono_aot_set_make_unreadable:
+ *
+ *   Set whenever to make all mmaped memory unreadable. In conjuction with a
+ * SIGSEGV handler, this is useful to find out which pages the runtime tries to read.
+ */
+void
+mono_aot_set_make_unreadable (gboolean unreadable)
+{
+       static int inited;
+
+       make_unreadable = unreadable;
+
+       if (make_unreadable && !inited) {
+               mono_counters_register ("AOT pagefaults", MONO_COUNTER_JIT | MONO_COUNTER_INT, &n_pagefaults);
+       }               
+}
+
+typedef struct {
+       MonoAotModule *module;
+       guint8 *ptr;
+} FindMapUserData;
+
+static void
+find_map (gpointer key, gpointer value, gpointer user_data)
+{
+       MonoAotModule *module = (MonoAotModule*)value;
+       FindMapUserData *data = (FindMapUserData*)user_data;
+
+       if (!data->module)
+               if ((data->ptr >= module->mem_begin) && (data->ptr < module->mem_end))
+                       data->module = module;
+}
+
+static MonoAotModule*
+find_module_for_addr (void *ptr)
+{
+       FindMapUserData data;
+
+       if (!make_unreadable)
+               return NULL;
+
+       data.module = NULL;
+       data.ptr = (guint8*)ptr;
+
+       mono_aot_lock ();
+       g_hash_table_foreach (aot_modules, (GHFunc)find_map, &data);
+       mono_aot_unlock ();
+
+       return data.module;
+}
+
+/*
+ * mono_aot_is_pagefault:
+ *
+ *   Should be called from a SIGSEGV signal handler to find out whenever @ptr is
+ * within memory allocated by this module.
+ */
+gboolean
+mono_aot_is_pagefault (void *ptr)
+{
+       if (!make_unreadable)
+               return FALSE;
+
+       /* 
+        * Not signal safe, but SIGSEGV's are synchronous, and
+        * this is only turned on by a MONO_DEBUG option.
+        */
+       return find_module_for_addr (ptr) != NULL;
+}
+
+/*
+ * mono_aot_handle_pagefault:
+ *
+ *   Handle a pagefault caused by an unreadable page by making it readable again.
+ */
+void
+mono_aot_handle_pagefault (void *ptr)
+{
+#ifndef PLATFORM_WIN32
+       guint8* start = (guint8*)ROUND_DOWN (((gssize)ptr), mono_pagesize ());
+       int res;
+
+       mono_aot_lock ();
+       res = mono_mprotect (start, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_WRITE|MONO_MMAP_EXEC);
+       g_assert (res == 0);
+
+       n_pagefaults ++;
+       mono_aot_unlock ();
+#endif
+}
 
 #else
 /* AOT disabled */