Rework decoding of method references in the AOT runtime.
authorZoltan Varga <vargaz@gmail.com>
Sun, 31 Oct 2010 00:44:33 +0000 (02:44 +0200)
committerZoltan Varga <vargaz@gmail.com>
Sun, 31 Oct 2010 00:46:00 +0000 (02:46 +0200)
   * Improve the hashing of methods to include generic arguments
   * Get rid of can_method_ref_match_method (), use a 'target' argument
     to decode_method_ref () instead.
   * Bump corlib file format version.

mono/mini/aot-compiler.c
mono/mini/aot-runtime.c
mono/mini/mini.h

index 5088324c0b5726311bde679d27731c9edcc81947..de08502f64fd5b19008601bb65a6e004834c3219 100644 (file)
@@ -5045,17 +5045,21 @@ mono_aot_method_hash (MonoMethod *method)
 {
        MonoMethodSignature *sig;
        MonoClass *klass;
-       int i;
+       int i, hindex;
        int hashes_count;
        guint32 *hashes_start, *hashes;
        guint32 a, b, c;
+       MonoGenericInst *ginst = NULL;
 
        /* Similar to the hash in mono_method_get_imt_slot () */
 
        sig = mono_method_signature (method);
 
-       hashes_count = sig->param_count + 5;
-       hashes_start = malloc (hashes_count * sizeof (guint32));
+       if (method->is_inflated)
+               ginst = ((MonoMethodInflated*)method)->context.method_inst;
+
+       hashes_count = sig->param_count + 5 + (ginst ? ginst->type_argc : 0);
+       hashes_start = g_malloc0 (hashes_count * sizeof (guint32));
        hashes = hashes_start;
 
        /* Some wrappers are assigned to random classes */
@@ -5081,10 +5085,16 @@ mono_aot_method_hash (MonoMethod *method)
                hashes [2] = mono_metadata_str_hash (method->name);
        hashes [3] = method->wrapper_type;
        hashes [4] = mono_aot_type_hash (sig->ret);
+       hindex = 5;
        for (i = 0; i < sig->param_count; i++) {
-               hashes [5 + i] = mono_aot_type_hash (sig->params [i]);
+               hashes [hindex ++] = mono_aot_type_hash (sig->params [i]);
        }
-       
+       if (ginst) {
+               for (i = 0; i < ginst->type_argc; ++i)
+                       hashes [hindex ++] = mono_aot_type_hash (ginst->type_argv [i]);
+       }               
+       g_assert (hindex == hashes_count);
+
        /* Setup internal state */
        a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
 
index 4bae87baf093fc3202762a285e180640bea38a59..fde819285bcd611b5bbb6e8f461d45a6ce04cb90 100644 (file)
@@ -465,51 +465,16 @@ decode_field_info (MonoAotModule *module, guint8 *buf, guint8 **endbuf)
 }
 
 /*
- * can_method_ref_match_method:
- *
- *   Determine if calling decode_resolve_method_ref on P could return the same method as 
- * METHOD. This is an optimization to avoid calling decode_resolve_method_ref () which
- * would create MonoMethods which are not needed etc.
- */
-static gboolean
-can_method_ref_match_method (MonoAotModule *module, guint8 *buf, MonoMethod *method)
-{
-       guint8 *p = buf;
-       guint32 image_index, value;
-
-       /* Keep this in sync with decode_method_ref () */
-       value = decode_value (p, &p);
-       image_index = value >> 24;
-
-       if (image_index == MONO_AOT_METHODREF_WRAPPER) {
-               guint32 wrapper_type;
-
-               if (!method->wrapper_type)
-                       return FALSE;
-
-               wrapper_type = decode_value (p, &p);
-
-               if (method->wrapper_type != wrapper_type)
-                       return FALSE;
-       } else if (image_index == MONO_AOT_METHODREF_WRAPPER_NAME) {
-               return FALSE;
-       } else if (image_index < MONO_AOT_METHODREF_MIN || image_index == MONO_AOT_METHODREF_METHODSPEC || image_index == MONO_AOT_METHODREF_GINST) {
-               if (method->wrapper_type)
-                       return FALSE;
-       }
-
-       return TRUE;
-}
-
-/*
- * decode_method_ref:
+ * decode_method_ref_with_target:
  *
  *   Decode a method reference, and return its image and token. This avoids loading
  * metadata for the method if the caller does not need it. If the method has no token,
- * then it is loaded from metadata and METHOD is set to the method instance.
+ * then it is loaded from metadata and METHOD is set to the method instance. If TARGET is non-NULL,
+ * abort decoding if it can be determined that the decoded method couldn't resolve to it, and
+ * return NULL.
  */
 static MonoImage*
-decode_method_ref (MonoAotModule *module, guint32 *token, MonoMethod **method, gboolean *no_aot_trampoline, guint8 *buf, guint8 **endbuf)
+decode_method_ref_with_target (MonoAotModule *module, guint32 *token, MonoMethod **method, MonoMethod *target, gboolean *no_aot_trampoline, guint8 *buf, guint8 **endbuf)
 {
        guint32 image_index, value;
        MonoImage *image = NULL;
@@ -530,11 +495,19 @@ decode_method_ref (MonoAotModule *module, guint32 *token, MonoMethod **method, g
                image_index = value >> 24;
        }
 
+       if (image_index < MONO_AOT_METHODREF_MIN || image_index == MONO_AOT_METHODREF_METHODSPEC || image_index == MONO_AOT_METHODREF_GINST) {
+               if (target && target->wrapper_type)
+                       return NULL;
+       }
+
        if (image_index == MONO_AOT_METHODREF_WRAPPER) {
                guint32 wrapper_type;
 
                wrapper_type = decode_value (p, &p);
 
+               if (target && target->wrapper_type != wrapper_type)
+                       return NULL;
+
                /* Doesn't matter */
                image = mono_defaults.corlib;
 
@@ -643,6 +616,8 @@ decode_method_ref (MonoAotModule *module, guint32 *token, MonoMethod **method, g
                        g_assert_not_reached ();
                }
        } else if (image_index == MONO_AOT_METHODREF_WRAPPER_NAME) {
+               if (target)
+                       return NULL;
                /* Can't decode these */
                g_assert_not_reached ();
        } else if (image_index == MONO_AOT_METHODREF_METHODSPEC) {
@@ -664,6 +639,9 @@ decode_method_ref (MonoAotModule *module, guint32 *token, MonoMethod **method, g
                if (!klass)
                        return NULL;
 
+               if (target && target->klass != klass)
+                       return NULL;
+
                image_index = decode_value (p, &p);
                *token = decode_value (p, &p);
 
@@ -732,17 +710,23 @@ decode_method_ref (MonoAotModule *module, guint32 *token, MonoMethod **method, g
        return image;
 }
 
+static MonoImage*
+decode_method_ref (MonoAotModule *module, guint32 *token, MonoMethod **method, gboolean *no_aot_trampoline, guint8 *buf, guint8 **endbuf)
+{
+       return decode_method_ref_with_target (module, token, method, NULL, no_aot_trampoline, buf, endbuf);
+}
+
 /*
- * decode_resolve_method_ref:
+ * decode_resolve_method_ref_with_target:
  *
  *   Similar to decode_method_ref, but resolve and return the method itself.
  */
 static MonoMethod*
-decode_resolve_method_ref (MonoAotModule *module, guint8 *buf, guint8 **endbuf)
+decode_resolve_method_ref_with_target (MonoAotModule *module, MonoMethod *target, guint8 *buf, guint8 **endbuf)
 {
        MonoMethod *method;
        guint32 token;
-       MonoImage *image = decode_method_ref (module, &token, &method, NULL, buf, endbuf);
+       MonoImage *image = decode_method_ref_with_target (module, &token, &method, target, NULL, buf, endbuf);
 
        if (method)
                return method;
@@ -752,6 +736,12 @@ decode_resolve_method_ref (MonoAotModule *module, guint8 *buf, guint8 **endbuf)
        return method;
 }
 
+static MonoMethod*
+decode_resolve_method_ref (MonoAotModule *module, guint8 *buf, guint8 **endbuf)
+{
+       return decode_resolve_method_ref_with_target (module, NULL, buf, endbuf);
+}
+
 static void
 create_cache_structure (void)
 {
@@ -2625,15 +2615,16 @@ find_extra_method_in_amodule (MonoAotModule *amodule, MonoMethod *method, const
                                index = value;
                                break;
                        }
-               } else if (can_method_ref_match_method (amodule, p, method)) {
+               } else {
+                       guint8 *orig_p = p;
+
                        mono_aot_lock ();
                        if (!amodule->method_ref_to_method)
                                amodule->method_ref_to_method = g_hash_table_new (NULL, NULL);
                        m = g_hash_table_lookup (amodule->method_ref_to_method, p);
                        mono_aot_unlock ();
                        if (!m) {
-                               guint8 *orig_p = p;
-                               m = decode_resolve_method_ref (amodule, p, &p);
+                               m = decode_resolve_method_ref_with_target (amodule, method, p, &p);
                                if (m) {
                                        mono_aot_lock ();
                                        g_hash_table_insert (amodule->method_ref_to_method, orig_p, m);
@@ -2658,11 +2649,10 @@ find_extra_method_in_amodule (MonoAotModule *amodule, MonoMethod *method, const
                        }
 
                        /* Methods decoded needlessly */
-                       /*
-                       if (m)
-                               printf ("%d %s %s\n", n_extra_decodes, mono_method_full_name (method, TRUE), mono_method_full_name (m, TRUE));
-                       */
-                       n_extra_decodes ++;
+                       if (m) {
+                               //printf ("%d %s %s %p\n", n_extra_decodes, mono_method_full_name (method, TRUE), mono_method_full_name (m, TRUE), orig_p);
+                               n_extra_decodes ++;
+                       }
                }
 
                if (next != 0)
index 27edc5efcae232fc62118c0d469857c3745f5679..6b7f50f8a3ed248fe1219e856222016d78bedad9 100644 (file)
@@ -111,7 +111,7 @@ typedef gint64 mgreg_t;
 #endif
 
 /* Version number of the AOT file format */
-#define MONO_AOT_FILE_VERSION "69"
+#define MONO_AOT_FILE_VERSION "70"
 
 //TODO: This is x86/amd64 specific.
 #define mono_simd_shuffle_mask(a,b,c,d) ((a) | ((b) << 2) | ((c) << 4) | ((d) << 6))