[w32handle] Stop returning 0 in every cases for locking/unlocking (#3926)
[mono.git] / mcs / tools / linker / profiler / link.c
1 /*
2  * link.c: a profiler to help the static linker
3  *
4  * Authors:
5  *   Jb Evain (jbevain@novell.com)
6  *
7  * (C) 2007 Novell, Inc. http://www.novell.com
8  *
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>
17
18 struct _MonoProfiler {
19         const char *output_file;
20         GHashTable *images;
21 };
22
23 typedef struct _LinkedImage {
24         MonoImage *image;
25         GHashTable *types;
26 } LinkedImage;
27
28 typedef struct _LinkedType {
29         MonoClass *klass;
30         GHashTable *methods;
31 } LinkedType;
32
33 typedef struct _LinkedMethod {
34         MonoMethod *method;
35 } LinkedMethod;
36
37 static void
38 link_append_class_name (GString *res, MonoClass *klass, gboolean include_namespace)
39 {
40         if (!klass) {
41                 g_string_append (res, "**unknown**");
42                 return;
43         }
44
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, '/');
48         }
49
50         if (include_namespace && *(mono_class_get_namespace (klass)))
51                 g_string_sprintfa (res, "%s.", mono_class_get_namespace (klass));
52
53         g_string_sprintfa (res, "%s", mono_class_get_name (klass));
54 }
55
56 static MonoType *
57 link_get_element_type (MonoType *type)
58 {
59         return mono_class_get_type (mono_class_get_element_class (mono_class_from_mono_type (type)));
60 }
61
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;
110         }
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;
128         }
129         if (mono_type_is_byref (type))
130                 g_string_append (res, "&amp;");
131 }
132
133 static char *
134 link_type_full_name (MonoType *type)
135 {
136         GString *str;
137         char *res;
138
139         str = g_string_new ("");
140         link_type_get_desc (str, type, TRUE);
141
142         res = g_strdup (str->str);
143         g_string_free (str, TRUE);
144         return res;
145 }
146
147 static char *
148 link_class_full_name (MonoClass *klass)
149 {
150         return link_type_full_name (mono_class_get_type (klass));
151 }
152
153 static char *
154 link_signature_get_desc (MonoMethodSignature *sig, gboolean include_namespace)
155 {
156         int i;
157         char *result;
158         GString *res = g_string_new ("");
159
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);
164         }
165         result = res->str;
166         g_string_free (res, FALSE);
167         return result;
168 }
169
170 static char *
171 link_method_signature (MonoMethod *method)
172 {
173         MonoMethodSignature *sig;
174         char *res;
175
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);
182
183         return res;
184 }
185
186 static char *
187 link_image_fullname (MonoImage *image)
188 {
189         MonoAssemblyName *name;
190         char *res;
191
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;
197 }
198
199 static LinkedType *
200 link_get_linked_type (LinkedImage *limage, MonoClass *klass)
201 {
202         LinkedType *ltype;
203
204         ltype = (LinkedType *) g_hash_table_lookup (limage->types, klass);
205
206         if (ltype)
207                 return ltype;
208
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;
214 }
215
216 static LinkedImage *
217 link_get_linked_image (MonoProfiler *prof, MonoImage *image)
218 {
219         LinkedImage *limage;
220
221         limage = (LinkedImage *) g_hash_table_lookup (prof->images, image);
222
223         if (limage)
224                 return limage;
225
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;
231 }
232
233 static void
234 link_method_leave (MonoProfiler *prof, MonoMethod *method)
235 {
236         MonoClass *klass;
237         MonoImage *image;
238
239         LinkedType *ltype;
240         LinkedImage *limage;
241         LinkedMethod *lmethod;
242
243         klass = mono_method_get_class (method);
244         image = mono_class_get_image (klass);
245
246         limage = link_get_linked_image (prof, image);
247         ltype = link_get_linked_type (limage, klass);
248
249         lmethod = (LinkedMethod *) g_hash_table_lookup (ltype->methods, method);
250         if (lmethod)
251                 return;
252
253         lmethod = g_new0 (LinkedMethod, 1);
254         lmethod->method = method;
255         g_hash_table_insert (ltype->methods, method, lmethod);
256 }
257
258 static void
259 link_free_member (gpointer key, gpointer value, gpointer data)
260 {
261         g_free (value);
262 }
263
264 static void
265 link_free_type (gpointer key, gpointer value, gpointer data)
266 {
267         LinkedType *type = (LinkedType *) value;
268
269         g_hash_table_foreach (type->methods, link_free_member, NULL);
270         g_free (type);
271 }
272
273 static void
274 link_free_image (gpointer key, gpointer value, gpointer data)
275 {
276         LinkedImage *image = (LinkedImage *) value;
277
278         g_hash_table_foreach (image->types, link_free_type, NULL);
279         g_free (image);
280 }
281
282 static void
283 link_print_method (gpointer key, gpointer value, gpointer data)
284 {
285         LinkedMethod *lmethod = (LinkedMethod *) value;
286         FILE *output = (FILE *) data;
287         char *signature;
288
289         signature = link_method_signature (lmethod->method);
290         fprintf (output, "\t\t\t<method signature=\"%s\" />\n", signature);
291         g_free (signature);
292 }
293
294 static void
295 link_print_type (gpointer key, gpointer value, gpointer data)
296 {
297         LinkedType *ltype = (LinkedType *) value;
298         FILE *output = (FILE *) data;
299         char *fullname;
300
301         fullname = link_class_full_name (ltype->klass);
302         fprintf (output, "\t\t<type fullname=\"%s\">\n", fullname);
303         g_free (fullname);
304
305         g_hash_table_foreach (ltype->methods, link_print_method, output);
306         fprintf (output, "\t\t</type>\n");
307 }
308
309 static void
310 link_print_image (gpointer key, gpointer value, gpointer data)
311 {
312         LinkedImage *limage = (LinkedImage *) value;
313         FILE *output = (FILE *) data;
314         char *fullname;
315
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");
321 }
322
323 static void
324 link_print_tree (MonoProfiler *prof)
325 {
326         FILE *output;
327
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);
333 }
334
335 static void
336 link_shutdown (MonoProfiler *prof)
337 {
338         link_print_tree (prof);
339         g_hash_table_foreach (prof->images, link_free_image, NULL);
340         g_free (prof);
341 }
342
343 void
344 mono_profiler_startup (const char *desc)
345 {
346         MonoProfiler *prof;
347
348         prof = g_new0 (MonoProfiler, 1);
349
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";
354
355         prof->images = g_hash_table_new (NULL, NULL);
356
357         mono_profiler_install (prof, link_shutdown);
358
359         mono_profiler_install_enter_leave (NULL, link_method_leave);
360
361         mono_profiler_set_events (MONO_PROFILE_ENTER_LEAVE);
362 }