2 * link.c: a profiler to help the static linker
5 * Jb Evain (jbevain@novell.com)
7 * (C) 2007 Novell, Inc. http://www.novell.com
12 #include <mono/metadata/assembly.h>
13 #include <mono/metadata/class.h>
14 #include <mono/metadata/image.h>
15 #include <mono/metadata/metadata.h>
16 #include <mono/metadata/profiler.h>
18 struct _MonoProfiler {
19 const char *output_file;
23 typedef struct _LinkedImage {
28 typedef struct _LinkedType {
33 typedef struct _LinkedMethod {
38 link_append_class_name (GString *res, MonoClass *klass, gboolean include_namespace)
41 g_string_append (res, "**unknown**");
45 if (mono_class_get_nesting_type (klass)) {
46 link_append_class_name (res, mono_class_get_nesting_type (klass), include_namespace);
47 g_string_append_c (res, '/');
50 if (include_namespace && *(mono_class_get_namespace (klass)))
51 g_string_sprintfa (res, "%s.", mono_class_get_namespace (klass));
53 g_string_sprintfa (res, "%s", mono_class_get_name (klass));
57 link_get_element_type (MonoType *type)
59 return mono_class_get_type (mono_class_get_element_class (mono_class_from_mono_type (type)));
63 link_type_get_desc (GString *res, MonoType *type, gboolean include_namespace) {
64 switch (mono_type_get_type (type)) {
66 g_string_append (res, "System.Void"); break;
68 g_string_append (res, "System.Char"); break;
69 case MONO_TYPE_BOOLEAN:
70 g_string_append (res, "System.Boolean"); break;
72 g_string_append (res, "System.Byte"); break;
74 g_string_append (res, "System.SByte"); break;
76 g_string_append (res, "System.UInt16"); break;
78 g_string_append (res, "System.Int16"); break;
80 g_string_append (res, "System.UInt32"); break;
82 g_string_append (res, "System.Int32"); break;
84 g_string_append (res, "System.UInt64"); break;
86 g_string_append (res, "System.Int64"); break;
88 g_string_append (res, "*()"); break;
90 g_string_append (res, "System.UIntPtr"); break;
92 g_string_append (res, "System.IntPtr"); break;
94 g_string_append (res, "System.Single"); break;
96 g_string_append (res, "System.Double"); break;
97 case MONO_TYPE_STRING:
98 g_string_append (res, "System.String"); break;
99 case MONO_TYPE_OBJECT:
100 g_string_append (res, "System.Object"); break;
102 link_type_get_desc (res, mono_type_get_ptr_type (type), include_namespace);
103 g_string_append_c (res, '*');
105 case MONO_TYPE_ARRAY: {
106 MonoClass *eklass = mono_class_get_element_class (mono_class_from_mono_type (type));
107 link_type_get_desc (res, mono_class_get_type (eklass), include_namespace);
108 g_string_sprintfa (res, "[%d]", mono_class_get_rank (eklass));
111 case MONO_TYPE_SZARRAY:
112 link_type_get_desc (res, link_get_element_type (type), include_namespace);
113 g_string_append (res, "[]");
115 case MONO_TYPE_CLASS:
116 case MONO_TYPE_VALUETYPE:
117 link_append_class_name (res, mono_type_get_class (type), include_namespace);
119 case MONO_TYPE_GENERICINST:
120 //link_type_get_desc (res, &type->data.generic_class->container_class->byval_arg, include_namespace); /* ? */
124 //g_string_append (res, type->data.generic_param->name); /* ? */
129 if (mono_type_is_byref (type))
130 g_string_append (res, "&");
134 link_type_full_name (MonoType *type)
139 str = g_string_new ("");
140 link_type_get_desc (str, type, TRUE);
142 res = g_strdup (str->str);
143 g_string_free (str, TRUE);
148 link_class_full_name (MonoClass *klass)
150 return link_type_full_name (mono_class_get_type (klass));
154 link_signature_get_desc (MonoMethodSignature *sig, gboolean include_namespace)
158 GString *res = g_string_new ("");
160 for (i = 0; i < sig->param_count; ++i) {
162 g_string_append_c (res, ',');
163 link_type_get_desc (res, sig->params [i], include_namespace);
166 g_string_free (res, FALSE);
171 link_method_signature (MonoMethod *method)
173 MonoMethodSignature *sig;
176 sig = mono_method_signature (method);
177 char *tmpsig = link_signature_get_desc (sig, TRUE);
178 res = g_strdup_printf ("%s %s(%s)",
179 link_type_full_name (mono_signature_get_return_type (sig)),
180 mono_method_get_name (method), tmpsig);
187 link_image_fullname (MonoImage *image)
189 MonoAssemblyName *name;
192 name = g_new0 (MonoAssemblyName, 1);
193 mono_assembly_fill_assembly_name (image, name);
194 res = mono_stringify_assembly_name (name);
200 link_get_linked_type (LinkedImage *limage, MonoClass *klass)
204 ltype = (LinkedType *) g_hash_table_lookup (limage->types, klass);
209 ltype = g_new0 (LinkedType, 1);
210 ltype->klass = klass;
211 ltype->methods = g_hash_table_new (NULL, NULL);
212 g_hash_table_insert (limage->types, klass, ltype);
217 link_get_linked_image (MonoProfiler *prof, MonoImage *image)
221 limage = (LinkedImage *) g_hash_table_lookup (prof->images, image);
226 limage = g_new0 (LinkedImage, 1);
227 limage->image = image;
228 limage->types = g_hash_table_new (NULL, NULL);
229 g_hash_table_insert (prof->images, image, limage);
234 link_method_leave (MonoProfiler *prof, MonoMethod *method)
241 LinkedMethod *lmethod;
243 klass = mono_method_get_class (method);
244 image = mono_class_get_image (klass);
246 limage = link_get_linked_image (prof, image);
247 ltype = link_get_linked_type (limage, klass);
249 lmethod = (LinkedMethod *) g_hash_table_lookup (ltype->methods, method);
253 lmethod = g_new0 (LinkedMethod, 1);
254 lmethod->method = method;
255 g_hash_table_insert (ltype->methods, method, lmethod);
259 link_free_member (gpointer key, gpointer value, gpointer data)
265 link_free_type (gpointer key, gpointer value, gpointer data)
267 LinkedType *type = (LinkedType *) value;
269 g_hash_table_foreach (type->methods, link_free_member, NULL);
274 link_free_image (gpointer key, gpointer value, gpointer data)
276 LinkedImage *image = (LinkedImage *) value;
278 g_hash_table_foreach (image->types, link_free_type, NULL);
283 link_print_method (gpointer key, gpointer value, gpointer data)
285 LinkedMethod *lmethod = (LinkedMethod *) value;
286 FILE *output = (FILE *) data;
289 signature = link_method_signature (lmethod->method);
290 fprintf (output, "\t\t\t<method signature=\"%s\" />\n", signature);
295 link_print_type (gpointer key, gpointer value, gpointer data)
297 LinkedType *ltype = (LinkedType *) value;
298 FILE *output = (FILE *) data;
301 fullname = link_class_full_name (ltype->klass);
302 fprintf (output, "\t\t<type fullname=\"%s\">\n", fullname);
305 g_hash_table_foreach (ltype->methods, link_print_method, output);
306 fprintf (output, "\t\t</type>\n");
310 link_print_image (gpointer key, gpointer value, gpointer data)
312 LinkedImage *limage = (LinkedImage *) value;
313 FILE *output = (FILE *) data;
316 fullname = link_image_fullname (limage->image);
317 fprintf (output, "\t<assembly fullname=\"%s\">\n", fullname);
319 g_hash_table_foreach (limage->types, link_print_type, output);
320 fprintf (output, "\t</assembly>\n");
324 link_print_tree (MonoProfiler *prof)
328 output = fopen (prof->output_file, "w");
329 fprintf (output, "<linker>\n");
330 g_hash_table_foreach (prof->images, link_print_image, output);
331 fprintf (output, "</linker>\n");
336 link_shutdown (MonoProfiler *prof)
338 link_print_tree (prof);
339 g_hash_table_foreach (prof->images, link_free_image, NULL);
344 mono_profiler_startup (const char *desc)
348 prof = g_new0 (MonoProfiler, 1);
350 if (strncmp ("link:", desc, 5) == 0 && desc [5])
351 prof->output_file = g_strdup (desc + 5);
353 prof->output_file = "link.xml";
355 prof->images = g_hash_table_new (NULL, NULL);
357 mono_profiler_install (prof, link_shutdown);
359 mono_profiler_install_enter_leave (NULL, link_method_leave);
361 mono_profiler_set_events (MONO_PROFILE_ENTER_LEAVE);