[runtime] Finish AOT method name mangler
authorAlexander Kyte <alkyte@microsoft.com>
Wed, 18 Jan 2017 15:50:40 +0000 (15:50 +0000)
committerAlexander Kyte <alexmkyte@gmail.com>
Fri, 17 Mar 2017 21:15:55 +0000 (17:15 -0400)
mono/metadata/debug-helpers.c
mono/metadata/metadata-internals.h
mono/mini/aot-compiler.c

index 3cac05ef00e9e8259f8c8f0a5afe872e643f2691..295cfd78b83ea05310a0db577b3c14277f6f83ba 100644 (file)
@@ -280,8 +280,8 @@ mono_signature_full_name (MonoMethodSignature *sig)
        return result;
 }
 
-static void
-ginst_get_desc (GString *str, MonoGenericInst *ginst)
+void
+mono_ginst_get_desc (GString *str, MonoGenericInst *ginst)
 {
        int i;
 
@@ -302,11 +302,11 @@ mono_context_get_desc (MonoGenericContext *context)
        g_string_append (str, "<");
 
        if (context->class_inst)
-               ginst_get_desc (str, context->class_inst);
+               mono_ginst_get_desc (str, context->class_inst);
        if (context->method_inst) {
                if (context->class_inst)
                        g_string_append (str, "; ");
-               ginst_get_desc (str, context->method_inst);
+               mono_ginst_get_desc (str, context->method_inst);
        }
 
        g_string_append (str, ">");
@@ -827,7 +827,7 @@ mono_method_get_name_full (MonoMethod *method, gboolean signature, gboolean ret,
                        g_string_append (str, "<");
                else
                        g_string_append (str, "[");
-               ginst_get_desc (str, ((MonoMethodInflated*)method)->context.method_inst);
+               mono_ginst_get_desc (str, ((MonoMethodInflated*)method)->context.method_inst);
                if (format == MONO_TYPE_NAME_FORMAT_IL)
                        g_string_append_c (str, '>');
                else
@@ -843,7 +843,7 @@ mono_method_get_name_full (MonoMethod *method, gboolean signature, gboolean ret,
                        g_string_append (str, "<");
                else
                        g_string_append (str, "[");
-               ginst_get_desc (str, container->context.method_inst);
+               mono_ginst_get_desc (str, container->context.method_inst);
                if (format == MONO_TYPE_NAME_FORMAT_IL)
                        g_string_append_c (str, '>');
                else
index cdd4a301dbad590e1e9187de5d9d558350dda983..1169caf8a8777819c4dcfd24530ca992554ebc88 100644 (file)
@@ -937,5 +937,8 @@ mono_loader_register_module (const char *name, MonoDl *module);
 gboolean
 mono_assembly_is_problematic_version (const char *name, guint16 major, guint16 minor, guint16 build, guint16 revision);
 
+void
+mono_ginst_get_desc (GString *str, MonoGenericInst *ginst);
+
 #endif /* __MONO_METADATA_INTERNALS_H__ */
 
index 59a123ed0573475ceb7e0551c9ee6c1b7171bbfb..df0f51cd7d5943c6f375195fecf94d9e9baa56a6 100644 (file)
@@ -8062,48 +8062,452 @@ append_mangled_signature (GString *s, MonoMethodSignature *sig)
        return TRUE;
 }
 
-/*
- * mono_aot_get_mangled_method_name:
- *
- *   Return a unique mangled name for METHOD, or NULL.
- */
-char*
-mono_aot_get_mangled_method_name (MonoMethod *method)
+static void
+append_mangled_wrapper_type (GString *s, guint32 wrapper_type) 
 {
-       WrapperInfo *info;
-       GString *s;
-       gboolean supported;
+       const char *label;
 
-       // FIXME: Add more cases
-       if (method->wrapper_type != MONO_WRAPPER_UNKNOWN)
-               return NULL;
-       info = mono_marshal_get_wrapper_info (method);
-       if (!(info && (info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG || info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_OUT_SIG)))
-               return NULL;
+       switch (wrapper_type) {
+       case MONO_WRAPPER_REMOTING_INVOKE:
+               label = "remoting_invoke";
+               break;
+       case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK:
+               label = "remoting_invoke_check";
+               break;
+       case MONO_WRAPPER_XDOMAIN_INVOKE:
+               label = "remoting_invoke_xdomain";
+               break;
+       case MONO_WRAPPER_PROXY_ISINST:
+               label = "proxy_isinst";
+               break;
+       case MONO_WRAPPER_LDFLD:
+               label = "ldfld";
+               break;
+       case MONO_WRAPPER_LDFLDA:
+               label = "ldflda";
+               break;
+       case MONO_WRAPPER_STFLD: 
+               label = "stfld";
+               break;
+       case MONO_WRAPPER_ALLOC:
+               label = "alloc";
+               break;
+       case MONO_WRAPPER_WRITE_BARRIER:
+               label = "write_barrier";
+               break;
+       case MONO_WRAPPER_STELEMREF:
+               label = "stelemref";
+               break;
+       case MONO_WRAPPER_UNKNOWN:
+               label = "unknown";
+               break;
+       case MONO_WRAPPER_MANAGED_TO_NATIVE:
+               label = "man2native";
+               break;
+       case MONO_WRAPPER_SYNCHRONIZED:
+               label = "synch";
+               break;
+       case MONO_WRAPPER_MANAGED_TO_MANAGED:
+               label = "man2man";
+               break;
+       case MONO_WRAPPER_CASTCLASS:
+               label = "castclass";
+               break;
+       case MONO_WRAPPER_RUNTIME_INVOKE:
+               label = "run_invoke";
+               break;
+       case MONO_WRAPPER_DELEGATE_INVOKE:
+               label = "del_inv";
+               break;
+       case MONO_WRAPPER_DELEGATE_BEGIN_INVOKE:
+               label = "del_beg_inv";
+               break;
+       case MONO_WRAPPER_DELEGATE_END_INVOKE:
+               label = "del_end_inv";
+               break;
+       case MONO_WRAPPER_NATIVE_TO_MANAGED:
+               label = "native2man";
+               break;
+       default:
+               g_assert_not_reached ();
+       }
 
-       s = g_string_new ("");
+       g_string_append_printf (s, "%s_", label);
+}
 
-       g_string_append_printf (s, "aot_method_w_");
+static void
+append_mangled_wrapper_subtype (GString *s, WrapperSubtype subtype) 
+{
+       const char *label;
 
-       switch (info->subtype) {
+       switch (subtype) 
+       {
+       case WRAPPER_SUBTYPE_NONE:
+               return;
+       case WRAPPER_SUBTYPE_ELEMENT_ADDR:
+               label = "elem_addr";
+               break;
+       case WRAPPER_SUBTYPE_STRING_CTOR:
+               label = "str_ctor";
+               break;
+       case WRAPPER_SUBTYPE_VIRTUAL_STELEMREF:
+               label = "virt_stelem";
+               break;
+       case WRAPPER_SUBTYPE_FAST_MONITOR_ENTER:
+               label = "fast_mon_enter";
+               break;
+       case WRAPPER_SUBTYPE_FAST_MONITOR_ENTER_V4:
+               label = "fast_mon_enter_4";
+               break;
+       case WRAPPER_SUBTYPE_FAST_MONITOR_EXIT:
+               label = "fast_monitor_exit";
+               break;
+       case WRAPPER_SUBTYPE_PTR_TO_STRUCTURE:
+               label = "ptr2struct";
+               break;
+       case WRAPPER_SUBTYPE_STRUCTURE_TO_PTR:
+               label = "struct2ptr";
+               break;
+       case WRAPPER_SUBTYPE_CASTCLASS_WITH_CACHE:
+               label = "castclass_w_cache";
+               break;
+       case WRAPPER_SUBTYPE_ISINST_WITH_CACHE:
+               label = "isinst_w_cache";
+               break;
+       case WRAPPER_SUBTYPE_RUNTIME_INVOKE_NORMAL:
+               label = "run_inv_norm";
+               break;
+       case WRAPPER_SUBTYPE_RUNTIME_INVOKE_DYNAMIC:
+               label = "run_inv_dyn";
+               break;
+       case WRAPPER_SUBTYPE_RUNTIME_INVOKE_DIRECT:
+               label = "run_inv_dir";
+               break;
+       case WRAPPER_SUBTYPE_RUNTIME_INVOKE_VIRTUAL:
+               label = "run_inv_vir";
+               break;
+       case WRAPPER_SUBTYPE_ICALL_WRAPPER:
+               label = "icall";
+               break;
+       case WRAPPER_SUBTYPE_NATIVE_FUNC_AOT:
+               label = "native_func_aot";
+               break;
+       case WRAPPER_SUBTYPE_PINVOKE:
+               label = "pinvoke";
+               break;
+       case WRAPPER_SUBTYPE_SYNCHRONIZED_INNER:
+               label = "synch_inner";
+               break;
+       case WRAPPER_SUBTYPE_GSHAREDVT_IN:
+               label = "gshared_in";
+               break;
+       case WRAPPER_SUBTYPE_GSHAREDVT_OUT:
+               label = "gshared_out";
+               break;
+       case WRAPPER_SUBTYPE_ARRAY_ACCESSOR:
+               label = "array_acc";
+               break;
+       case WRAPPER_SUBTYPE_GENERIC_ARRAY_HELPER:
+               label = "generic_arry_help";
+               break;
+       case WRAPPER_SUBTYPE_DELEGATE_INVOKE_VIRTUAL:
+               label = "del_inv_virt";
+               break;
+       case WRAPPER_SUBTYPE_DELEGATE_INVOKE_BOUND:
+               label = "del_inv_bound";
+               break;
        case WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG:
-               g_string_append_printf (s, "gsharedvt_in_");
+               label = "gsharedvt_in_sig";
                break;
        case WRAPPER_SUBTYPE_GSHAREDVT_OUT_SIG:
-               g_string_append_printf (s, "gsharedvt_out_");
+               label = "gsharedvt_out_sig";
                break;
        default:
                g_assert_not_reached ();
+       }
+
+       g_string_append_printf (s, "%s_", label);
+}
+
+static char *
+sanitize_mangled_string (const char *input)
+{
+       GString *s = g_string_new ("");
+
+       for (int i=0; input [i] != '\0'; i++) {
+               char c = input [i];
+               switch (c) {
+               case '.':
+                       g_string_append (s, "_dot_");
+                       break;
+               case ' ':
+                       g_string_append (s, "_");
+                       break;
+               case '`':
+                       g_string_append (s, "_bt_");
+                       break;
+               case '<':
+                       g_string_append (s, "_le_");
+                       break;
+               case '>':
+                       g_string_append (s, "_gt_");
+                       break;
+               case '/':
+                       g_string_append (s, "_sl_");
+                       break;
+               case '[':
+                       g_string_append (s, "_lbrack_");
+                       break;
+               case ']':
+                       g_string_append (s, "_rbrack_");
+                       break;
+               case '(':
+                       g_string_append (s, "_lparen_");
+                       break;
+               case '-':
+                       g_string_append (s, "_dash_");
+                       break;
+               case ')':
+                       g_string_append (s, "_rparen_");
+                       break;
+               case ',':
+                       g_string_append (s, "_comma_");
+                       break;
+               default:
+                       g_string_append_c (s, c);
+               }
+       }
+
+       return g_string_free (s, FALSE);
+}
+
+static gboolean
+append_mangled_klass (GString *s, MonoClass *klass)
+{
+       char *klass_desc = mono_class_full_name (klass);
+       g_string_append_printf (s, "_%s_%s_", klass->name_space, klass_desc);
+       g_free (klass_desc);
+
+       // Success
+       return TRUE;
+}
+
+static gboolean
+append_mangled_method (GString *s, MonoMethod *method);
+
+static gboolean
+append_mangled_wrapper (GString *s, MonoMethod *method) 
+{
+       gboolean success = TRUE;
+       WrapperInfo *info = mono_marshal_get_wrapper_info (method);
+       g_string_append_printf (s, "wrapper_");
+
+       append_mangled_wrapper_type (s, method->wrapper_type);
+
+       switch (method->wrapper_type) {
+       case MONO_WRAPPER_REMOTING_INVOKE:
+       case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK:
+       case MONO_WRAPPER_XDOMAIN_INVOKE: {
+               MonoMethod *m = mono_marshal_method_from_wrapper (method);
+               g_assert (m);
+               success = success && append_mangled_method (s, m);
+               break;
+       }
+       case MONO_WRAPPER_PROXY_ISINST:
+       case MONO_WRAPPER_LDFLD:
+       case MONO_WRAPPER_LDFLDA:
+       case MONO_WRAPPER_STFLD: {
+               g_assert (info);
+               success = success && append_mangled_klass (s, info->d.proxy.klass);
+               break;
+       }
+       case MONO_WRAPPER_ALLOC: {
+               /* The GC name is saved once in MonoAotFileInfo */
+               g_assert (info->d.alloc.alloc_type != -1);
+               g_string_append_printf (s, "%d_", info->d.alloc.alloc_type);
+               // SlowAlloc, etc
+               g_string_append_printf (s, "%s_", method->name);
+               break;
+       }
+       case MONO_WRAPPER_WRITE_BARRIER: {
+               break;
+       }
+       case MONO_WRAPPER_STELEMREF: {
+               append_mangled_wrapper_subtype (s, info->subtype);
+               if (info->subtype == WRAPPER_SUBTYPE_VIRTUAL_STELEMREF)
+                       g_string_append_printf (s, "%d", info->d.virtual_stelemref.kind);
+               break;
+       }
+       case MONO_WRAPPER_UNKNOWN: {
+               append_mangled_wrapper_subtype (s, info->subtype);
+               if (info->subtype == WRAPPER_SUBTYPE_PTR_TO_STRUCTURE ||
+                       info->subtype == WRAPPER_SUBTYPE_STRUCTURE_TO_PTR)
+                       success = success && append_mangled_klass (s, method->klass);
+               else if (info->subtype == WRAPPER_SUBTYPE_SYNCHRONIZED_INNER)
+                       success = success && append_mangled_method (s, info->d.synchronized_inner.method);
+               else if (info->subtype == WRAPPER_SUBTYPE_ARRAY_ACCESSOR)
+                       success = success && append_mangled_method (s, info->d.array_accessor.method);
+               else if (info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG)
+                       append_mangled_signature (s, info->d.gsharedvt.sig);
+               else if (info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_OUT_SIG)
+                       append_mangled_signature (s, info->d.gsharedvt.sig);
+               break;
+       }
+       case MONO_WRAPPER_MANAGED_TO_NATIVE: {
+               append_mangled_wrapper_subtype (s, info->subtype);
+               if (info->subtype == WRAPPER_SUBTYPE_ICALL_WRAPPER) {
+                       g_string_append_printf (s, "%s", method->name);
+               } else if (info->subtype == WRAPPER_SUBTYPE_NATIVE_FUNC_AOT) {
+                       success = success && append_mangled_method (s, info->d.managed_to_native.method);
+               } else {
+                       g_assert (info->subtype == WRAPPER_SUBTYPE_NONE || info->subtype == WRAPPER_SUBTYPE_PINVOKE);
+                       success = success && append_mangled_method (s, info->d.managed_to_native.method);
+               }
+               break;
+       }
+       case MONO_WRAPPER_SYNCHRONIZED: {
+               MonoMethod *m;
+
+               m = mono_marshal_method_from_wrapper (method);
+               g_assert (m);
+               g_assert (m != method);
+               success = success && append_mangled_method (s, m);
+               break;
+       }
+       case MONO_WRAPPER_MANAGED_TO_MANAGED: {
+               append_mangled_wrapper_subtype (s, info->subtype);
+
+               if (info->subtype == WRAPPER_SUBTYPE_ELEMENT_ADDR) {
+                       g_string_append_printf (s, "%d_", info->d.element_addr.rank);
+                       g_string_append_printf (s, "%d_", info->d.element_addr.elem_size);
+               } else if (info->subtype == WRAPPER_SUBTYPE_STRING_CTOR) {
+                       success = success && append_mangled_method (s, info->d.string_ctor.method);
+               } else {
+                       g_assert_not_reached ();
+               }
+               break;
+       }
+       case MONO_WRAPPER_CASTCLASS: {
+               append_mangled_wrapper_subtype (s, info->subtype);
+               break;
+       }
+       case MONO_WRAPPER_RUNTIME_INVOKE: {
+               append_mangled_wrapper_subtype (s, info->subtype);
+               if (info->subtype == WRAPPER_SUBTYPE_RUNTIME_INVOKE_DIRECT || info->subtype == WRAPPER_SUBTYPE_RUNTIME_INVOKE_VIRTUAL)
+                       success = success && append_mangled_method (s, info->d.runtime_invoke.method);
+               else if (info->subtype == WRAPPER_SUBTYPE_RUNTIME_INVOKE_NORMAL)
+                       success = success && append_mangled_signature (s, info->d.runtime_invoke.sig);
+               break;
+       }
+       case MONO_WRAPPER_DELEGATE_INVOKE:
+       case MONO_WRAPPER_DELEGATE_BEGIN_INVOKE:
+       case MONO_WRAPPER_DELEGATE_END_INVOKE: {
+               if (method->is_inflated) {
+                       /* These wrappers are identified by their class */
+                       g_string_append_printf (s, "i_");
+                       success = success && append_mangled_klass (s, method->klass);
+               } else {
+                       WrapperInfo *info = mono_marshal_get_wrapper_info (method);
+
+                       g_string_append_printf (s, "u_");
+                       if (method->wrapper_type == MONO_WRAPPER_DELEGATE_INVOKE)
+                               append_mangled_wrapper_subtype (s, info->subtype);
+                       g_string_append_printf (s, "u_sigstart");
+               }
                break;
        }
+       case MONO_WRAPPER_NATIVE_TO_MANAGED: {
+               g_assert (info);
+               success = success && append_mangled_method (s, info->d.native_to_managed.method);
+               success = success && append_mangled_klass (s, method->klass);
+               break;
+       }
+       default:
+               g_assert_not_reached ();
+       }
+       return success && append_mangled_signature (s, mono_method_signature (method));
+}
+
+static void
+append_mangled_context (GString *str, MonoGenericContext *context)
+{
+       GString *res = g_string_new ("");
+
+       g_string_append_printf (res, "gens_");
+       g_string_append (res, "00");
+
+       gboolean good = context->class_inst && context->class_inst->type_argc > 0;
+       good = good || (context->method_inst && context->method_inst->type_argc > 0);
+       g_assert (good);
+
+       if (context->class_inst)
+               mono_ginst_get_desc (res, context->class_inst);
+       if (context->method_inst) {
+               if (context->class_inst)
+                       g_string_append (res, "11");
+               mono_ginst_get_desc (res, context->method_inst);
+       }
+       g_string_append_printf (str, "gens_%s", res->str);
+}      
+
+static gboolean
+append_mangled_method (GString *s, MonoMethod *method)
+{
+       if (method->wrapper_type)
+               return append_mangled_wrapper (s, method);
+
+       g_string_append_printf (s, "%s_", method->klass->image->assembly->aname.name);
+
+       if (method->is_inflated) {
+               g_string_append_printf (s, "inflated_");
+               MonoMethodInflated *imethod = (MonoMethodInflated*) method;
+               g_assert (imethod->context.class_inst != NULL || imethod->context.method_inst != NULL);
+
+               append_mangled_context (s, &imethod->context);
+               g_string_append_printf (s, "_declared_by_");
+               append_mangled_method (s, imethod->declaring);
+       } else if (method->is_generic) {
+               g_string_append_printf (s, "generic_");
+               append_mangled_klass (s, method->klass);
+               g_string_append_printf (s, "_%s_", method->name);
+
+               MonoGenericContainer *container = mono_method_get_generic_container (method);
+               g_string_append_printf (s, "_%s");
+               append_mangled_context (s, &container->context);
+
+               return append_mangled_signature (s, mono_method_signature (method));
+       } else {
+               g_string_append_printf (s, "_");
+               append_mangled_klass (s, method->klass);
+               g_string_append_printf (s, "_%s_", method->name);
+               if (!append_mangled_signature (s, mono_method_signature (method))) {
+                       g_string_free (s, TRUE);
+                       return FALSE;
+               }
+       }
+
+       return TRUE;
+}
 
-       supported = append_mangled_signature (s, info->d.gsharedvt.sig);
-       if (!supported) {
+/*
+ * mono_aot_get_mangled_method_name:
+ *
+ *   Return a unique mangled name for METHOD, or NULL.
+ */
+char*
+mono_aot_get_mangled_method_name (MonoMethod *method)
+{
+       GString *s = g_string_new ("aot_");
+       if (!append_mangled_method (s, method)) {
                g_string_free (s, TRUE);
                return NULL;
+       } else {
+               char *out = g_string_free (s, FALSE);
+               // Scrub method and class names
+               char *cleaned = sanitize_mangled_string (out);
+               g_free (out);
+               return cleaned;
        }
-
-       return g_string_free (s, FALSE);
 }
 
 gboolean