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
);