2010-05-31 Jb Evain <jbevain@novell.com>
[mcs.git] / tools / linker / profiler / link.c
blobf81e251bea656e11529f62e6c847e3a25e6f6a65
1 /*
2 * link.c: a profiler to help the static linker
4 * Authors:
5 * Jb Evain (jbevain@novell.com)
7 * (C) 2007 Novell, Inc. http://www.novell.com
9 */
10 #include <glib.h>
11 #include <string.h>
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;
20 GHashTable *images;
23 typedef struct _LinkedImage {
24 MonoImage *image;
25 GHashTable *types;
26 } LinkedImage;
28 typedef struct _LinkedType {
29 MonoClass *klass;
30 GHashTable *methods;
31 } LinkedType;
33 typedef struct _LinkedMethod {
34 MonoMethod *method;
35 } LinkedMethod;
37 static void
38 link_append_class_name (GString *res, MonoClass *klass, gboolean include_namespace)
40 if (!klass) {
41 g_string_append (res, "**unknown**");
42 return;
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));
56 static MonoType *
57 link_get_element_type (MonoType *type)
59 return mono_class_get_type (mono_class_get_element_class (mono_class_from_mono_type (type)));
62 static void
63 link_type_get_desc (GString *res, MonoType *type, gboolean include_namespace) {
64 switch (mono_type_get_type (type)) {
65 case MONO_TYPE_VOID:
66 g_string_append (res, "System.Void"); break;
67 case MONO_TYPE_CHAR:
68 g_string_append (res, "System.Char"); break;
69 case MONO_TYPE_BOOLEAN:
70 g_string_append (res, "System.Boolean"); break;
71 case MONO_TYPE_U1:
72 g_string_append (res, "System.Byte"); break;
73 case MONO_TYPE_I1:
74 g_string_append (res, "System.SByte"); break;
75 case MONO_TYPE_U2:
76 g_string_append (res, "System.UInt16"); break;
77 case MONO_TYPE_I2:
78 g_string_append (res, "System.Int16"); break;
79 case MONO_TYPE_U4:
80 g_string_append (res, "System.UInt32"); break;
81 case MONO_TYPE_I4:
82 g_string_append (res, "System.Int32"); break;
83 case MONO_TYPE_U8:
84 g_string_append (res, "System.UInt64"); break;
85 case MONO_TYPE_I8:
86 g_string_append (res, "System.Int64"); break;
87 case MONO_TYPE_FNPTR:
88 g_string_append (res, "*()"); break;
89 case MONO_TYPE_U:
90 g_string_append (res, "System.UIntPtr"); break;
91 case MONO_TYPE_I:
92 g_string_append (res, "System.IntPtr"); break;
93 case MONO_TYPE_R4:
94 g_string_append (res, "System.Single"); break;
95 case MONO_TYPE_R8:
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;
101 case MONO_TYPE_PTR:
102 link_type_get_desc (res, mono_type_get_ptr_type (type), include_namespace);
103 g_string_append_c (res, '*');
104 break;
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));
109 break;
111 case MONO_TYPE_SZARRAY:
112 link_type_get_desc (res, link_get_element_type (type), include_namespace);
113 g_string_append (res, "[]");
114 break;
115 case MONO_TYPE_CLASS:
116 case MONO_TYPE_VALUETYPE:
117 link_append_class_name (res, mono_type_get_class (type), include_namespace);
118 break;
119 case MONO_TYPE_GENERICINST:
120 //link_type_get_desc (res, &type->data.generic_class->container_class->byval_arg, include_namespace); /* ? */
121 break;
122 case MONO_TYPE_VAR:
123 case MONO_TYPE_MVAR:
124 //g_string_append (res, type->data.generic_param->name); /* ? */
125 break;
126 default:
127 break;
129 if (mono_type_is_byref (type))
130 g_string_append (res, "&amp;");
133 static char *
134 link_type_full_name (MonoType *type)
136 GString *str;
137 char *res;
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);
144 return res;
147 static char *
148 link_class_full_name (MonoClass *klass)
150 return link_type_full_name (mono_class_get_type (klass));
153 static char *
154 link_signature_get_desc (MonoMethodSignature *sig, gboolean include_namespace)
156 int i;
157 char *result;
158 GString *res = g_string_new ("");
160 for (i = 0; i < sig->param_count; ++i) {
161 if (i > 0)
162 g_string_append_c (res, ',');
163 link_type_get_desc (res, sig->params [i], include_namespace);
165 result = res->str;
166 g_string_free (res, FALSE);
167 return result;
170 static char *
171 link_method_signature (MonoMethod *method)
173 MonoMethodSignature *sig;
174 char *res;
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);
181 g_free (tmpsig);
183 return res;
186 static char *
187 link_image_fullname (MonoImage *image)
189 MonoAssemblyName *name;
190 char *res;
192 name = g_new0 (MonoAssemblyName, 1);
193 mono_assembly_fill_assembly_name (image, name);
194 res = mono_stringify_assembly_name (name);
195 g_free (name);
196 return res;
199 static LinkedType *
200 link_get_linked_type (LinkedImage *limage, MonoClass *klass)
202 LinkedType *ltype;
204 ltype = (LinkedType *) g_hash_table_lookup (limage->types, klass);
206 if (ltype)
207 return ltype;
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);
213 return ltype;
216 static LinkedImage *
217 link_get_linked_image (MonoProfiler *prof, MonoImage *image)
219 LinkedImage *limage;
221 limage = (LinkedImage *) g_hash_table_lookup (prof->images, image);
223 if (limage)
224 return limage;
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);
230 return limage;
233 static void
234 link_method_leave (MonoProfiler *prof, MonoMethod *method)
236 MonoClass *klass;
237 MonoImage *image;
239 LinkedType *ltype;
240 LinkedImage *limage;
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);
250 if (lmethod)
251 return;
253 lmethod = g_new0 (LinkedMethod, 1);
254 lmethod->method = method;
255 g_hash_table_insert (ltype->methods, method, lmethod);
258 static void
259 link_free_member (gpointer key, gpointer value, gpointer data)
261 g_free (value);
264 static void
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);
270 g_free (type);
273 static void
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);
279 g_free (image);
282 static void
283 link_print_method (gpointer key, gpointer value, gpointer data)
285 LinkedMethod *lmethod = (LinkedMethod *) value;
286 FILE *output = (FILE *) data;
287 char *signature;
289 signature = link_method_signature (lmethod->method);
290 fprintf (output, "\t\t\t<method signature=\"%s\" />\n", signature);
291 g_free (signature);
294 static void
295 link_print_type (gpointer key, gpointer value, gpointer data)
297 LinkedType *ltype = (LinkedType *) value;
298 FILE *output = (FILE *) data;
299 char *fullname;
301 fullname = link_class_full_name (ltype->klass);
302 fprintf (output, "\t\t<type fullname=\"%s\">\n", fullname);
303 g_free (fullname);
305 g_hash_table_foreach (ltype->methods, link_print_method, output);
306 fprintf (output, "\t\t</type>\n");
309 static void
310 link_print_image (gpointer key, gpointer value, gpointer data)
312 LinkedImage *limage = (LinkedImage *) value;
313 FILE *output = (FILE *) data;
314 char *fullname;
316 fullname = link_image_fullname (limage->image);
317 fprintf (output, "\t<assembly fullname=\"%s\">\n", fullname);
318 g_free (fullname);
319 g_hash_table_foreach (limage->types, link_print_type, output);
320 fprintf (output, "\t</assembly>\n");
323 static void
324 link_print_tree (MonoProfiler *prof)
326 FILE *output;
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");
332 fclose (output);
335 static void
336 link_shutdown (MonoProfiler *prof)
338 link_print_tree (prof);
339 g_hash_table_foreach (prof->images, link_free_image, NULL);
340 g_free (prof);
343 void
344 mono_profiler_startup (const char *desc)
346 MonoProfiler *prof;
348 prof = g_new0 (MonoProfiler, 1);
350 if (strncmp ("link:", desc, 5) == 0 && desc [5])
351 prof->output_file = g_strdup (desc + 5);
352 else
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);