2009-05-14 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / aot-compiler.c
index bfa9f5de22a43386db5f53f534e8b5b4891c8165..d3918ad382477675cdf3dd84a7fcc5c9137a7277 100644 (file)
@@ -2008,14 +2008,29 @@ emit_method_code (MonoAotCompile *acfg, MonoCompile *cfg)
        emit_alignment (acfg, func_alignment);
        emit_label (acfg, symbol);
 
-       if (acfg->aot_opts.write_symbols && !acfg->aot_opts.nodebug && acfg->use_bin_writer) {
-               char *full_name;
-               /* Emit a local symbol into the symbol table */
-               full_name = mono_method_full_name (method, TRUE);
+       if (acfg->aot_opts.write_symbols && !acfg->aot_opts.nodebug) {
+               char *name1, *name2;
+               int i, j, len;
+
+               name1 = mono_method_full_name (method, TRUE);
+               len = strlen (name1);
+               name2 = malloc (len + 1);
+               j = 0;
+               for (i = 0; i < len; ++i) {
+                       if (isalnum (name1 [i])) {
+                               name2 [j ++] = name1 [i];
+                       } else if (name1 [i] == ' ' && name1 [i + 1] == '(' && name1 [i + 2] == ')') {
+                               i += 2;
+                       } else if (name1 [i] == '(' || name1 [i] == ')') {
+                       } else
+                               name2 [j ++] = '_';
+               }
+               name2 [j] = '\0';
                sprintf (symbol, ".Lme_%x", method_index);
-               emit_local_symbol (acfg, full_name, symbol, TRUE);
-               emit_label (acfg, full_name);
-               g_free (full_name);
+               emit_local_symbol (acfg, name2, symbol, TRUE);
+               emit_label (acfg, name2);
+               g_free (name1);
+               g_free (name2);
        }
 
        if (cfg->verbose_level > 0)
@@ -3461,6 +3476,25 @@ mono_aot_str_hash (gconstpointer v1)
        return hash;
 } 
 
+#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
+#define mix(a,b,c) { \
+       a -= c;  a ^= rot(c, 4);  c += b; \
+       b -= a;  b ^= rot(a, 6);  a += c; \
+       c -= b;  c ^= rot(b, 8);  b += a; \
+       a -= c;  a ^= rot(c,16);  c += b; \
+       b -= a;  b ^= rot(a,19);  a += c; \
+       c -= b;  c ^= rot(b, 4);  b += a; \
+}
+#define final(a,b,c) { \
+       c ^= b; c -= rot(b,14); \
+       a ^= c; a -= rot(c,11); \
+       b ^= a; b -= rot(a,25); \
+       c ^= b; c -= rot(b,16); \
+       a ^= c; a -= rot(c,4);  \
+       b ^= a; b -= rot(a,14); \
+       c ^= b; c -= rot(b,24); \
+}
+
 /*
  * mono_aot_method_hash:
  *
@@ -3469,19 +3503,78 @@ mono_aot_str_hash (gconstpointer v1)
 guint32
 mono_aot_method_hash (MonoMethod *method)
 {
-       guint32 hash;
+       MonoMethodSignature *sig;
+       MonoClass *klass;
+       int i;
+       int hashes_count;
+       guint32 *hashes_start, *hashes;
+       guint32 a, b, c;
 
-       if (method->wrapper_type) {
-               hash = mono_aot_str_hash (method->name);
-       } else {
-               char *full_name = mono_method_full_name (method, TRUE);
-               // FIXME: Improve this (changing this requires bumping MONO_AOT_FILE_VERSION)
-               hash = mono_aot_str_hash (full_name);
+       /* 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));
+       hashes = hashes_start;
+
+       /* Some wrappers are assigned to random classes */
+       if (!method->wrapper_type || method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)
+               klass = method->klass;
+       else
+               klass = mono_defaults.object_class;
+
+       if (!method->wrapper_type) {
+               char *full_name = mono_type_full_name (&klass->byval_arg);
+
+               hashes [0] = mono_aot_str_hash (full_name);
+               hashes [1] = 0;
                g_free (full_name);
+       } else {
+               hashes [0] = mono_aot_str_hash (klass->name);
+               hashes [1] = mono_aot_str_hash (klass->name_space);
+       }
+       hashes [2] = mono_aot_str_hash (method->name);
+       hashes [3] = method->wrapper_type;
+       hashes [4] = mono_metadata_type_hash (sig->ret);
+       for (i = 0; i < sig->param_count; i++) {
+               /* This is needed for some reason */
+               if (method->wrapper_type && sig->params [i]->type == MONO_TYPE_GENERICINST)
+                       hashes [5 + i] = MONO_TYPE_GENERICINST;
+               else
+                       hashes [5 + i] = mono_metadata_type_hash (sig->params [i]);
+       }
+       
+       /* Setup internal state */
+       a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
+
+       /* Handle most of the hashes */
+       while (hashes_count > 3) {
+               a += hashes [0];
+               b += hashes [1];
+               c += hashes [2];
+               mix (a,b,c);
+               hashes_count -= 3;
+               hashes += 3;
        }
 
-       return hash;
+       /* Handle the last 3 hashes (all the case statements fall through) */
+       switch (hashes_count) { 
+       case 3 : c += hashes [2];
+       case 2 : b += hashes [1];
+       case 1 : a += hashes [0];
+               final (a,b,c);
+       case 0: /* nothing left to add */
+               break;
+       }
+       
+       free (hashes_start);
+       
+       return c;
 }
+#undef rot
+#undef mix
+#undef final
 
 /*
  * mono_aot_wrapper_name: