Added tests for Task.WhenAll w/ empty list
[mono.git] / mcs / tools / ildasm / ildasm.cs
1 using System;
2 using System.IO;
3 using System.Text;
4 using System.Collections.Generic;
5 using System.Linq;
6 using Mono.Cecil;
7 using Mono.Cecil.Cil;
8 using Mono;
9
10 public partial class ILDAsm
11 {
12         public static int Main (String[] args) {
13                 if (args.Length != 1) {
14                         Console.Error.WriteLine ("Usage: ildasm <assembly file>");
15                         return 1;
16                 }
17
18                 var inst = new ILDAsm ();
19                 return inst.Run (args);
20         }
21
22         public AssemblyDefinition ad;
23         public ModuleDefinition main;
24         public TextWriter os;
25         public int indent;
26         public List<FieldDefinition> fields_with_rva = new List<FieldDefinition> ();
27
28         public void WriteLine () {
29                 os.WriteLine ();
30         }
31
32         public void WriteLine (String s) {
33                 for (int i = 0; i < indent; ++i)
34                         os.Write ("  ");
35                 os.WriteLine (s);
36         }
37
38         public int Run (String[] args) {
39                 ad = AssemblyDefinition.ReadAssembly (args [0]);
40
41                 main = ad.MainModule;
42
43                 os = Console.Out;
44
45                 // Emit assembly references
46                 EmitAssemblyReferences ();
47                 EmitAssembly ();
48                 EmitModule ();
49                 foreach (var typedef in main.Types) {
50                         // FIXME:
51                         if (typedef.Name == "<Module>")
52                                 EmitGlobals (typedef);
53                         else
54                                 EmitType (typedef);
55                 }
56                 EmitData ();
57
58                 return 0;
59         }
60
61         string EscapeName (string s) {
62                 bool escape = false;
63
64                 if (s.Contains ("/")) {
65                         string[] parts = s.Split ('/');
66                         var sb = new StringBuilder ();
67                         for (int i = 0; i < parts.Length; ++i) {
68                                 if (i > 0)
69                                         sb.Append ("/");
70                                 sb.Append (EscapeName (parts [i]));
71                         }
72                         return sb.ToString ();
73                 }
74                         
75                 foreach (char c in s) {
76                         if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || (c == '_') || (c == '.') || (c == '`')))
77                                 escape = true;
78                 }
79                 if (!escape && keyword_table.ContainsKey (s))
80                         escape = true;
81                 if (escape)
82                         return "'" + s + "'";
83                 else
84                         return s;
85         }
86
87         string EscapeString (string s) {
88                 return s.Replace ("\\", "\\\\").Replace ("\"", "\\\"");
89         }
90
91         void EmitScope (IMetadataScope s, StringBuilder sb) {
92                 if (s is AssemblyNameReference) {
93                         AssemblyNameReference aname = (s as AssemblyNameReference);
94                         sb.Append ("[" + EscapeName (aname.Name) + "]");
95                 } else if (s is ModuleDefinition) {
96                         if (s != main)
97                                 throw new NotImplementedException ();
98                 } else {
99                         throw new NotImplementedException (s.GetType ().ToString ());
100                 }
101         }
102
103         string StringifyTypeRef (TypeReference t) {
104                 switch (t.MetadataType) {
105                 case MetadataType.Void:
106                         return "void";
107                 case MetadataType.Boolean:
108                         return "bool";
109                 case MetadataType.Char:
110                         return "char";
111                 case MetadataType.SByte:
112                         return "int8";
113                 case MetadataType.Byte:
114                         return "unsigned int8";
115                 case MetadataType.Int16:
116                         return "int16";
117                 case MetadataType.UInt16:
118                         return "unsigned int16";
119                 case MetadataType.Int32:
120                         return "int32";
121                 case MetadataType.UInt32:
122                         return "unsigned int32";
123                 case MetadataType.Int64:
124                         return "int64";
125                 case MetadataType.UInt64:
126                         return "unsigned int64";
127                 case MetadataType.Single:
128                         return "float32";
129                 case MetadataType.Double:
130                         return "float64";
131                 case MetadataType.String:
132                         return "string";
133                 case MetadataType.IntPtr:
134                         return "native int";
135                 case MetadataType.UIntPtr:
136                         //return "unsigned native int";
137                         return "[mscorlib]System.UIntPtr";
138                 case MetadataType.TypedByReference:
139                         return "typedref";
140                 case MetadataType.Class:
141                 case MetadataType.Object:
142                 case MetadataType.ValueType: {
143                         var sb = new StringBuilder ();
144                         IMetadataScope s = t.Scope;
145                         if (t.MetadataType == MetadataType.ValueType)
146                                 sb.Append ("valuetype ");
147                         else
148                                 sb.Append ("class ");
149                         EmitScope (s, sb);
150                         sb.Append (EscapeName (t.FullName));
151                         return sb.ToString ();
152                 }
153                 case MetadataType.Array: {
154                         ArrayType at = (t as ArrayType);
155                         
156                         if (at.IsVector)
157                                 return StringifyTypeRef (at.ElementType) + "[]";
158
159                         var suffix = new StringBuilder ();
160                         suffix.Append ("[");
161                         for (int i = 0; i < at.Dimensions.Count; i++) {
162                                 if (i > 0)
163                                         suffix.Append (",");
164
165                                 suffix.Append (at.Dimensions [i].ToString ());
166                         }
167                         suffix.Append ("]");
168
169                         return StringifyTypeRef (at.ElementType) + suffix;
170                 }
171                 case MetadataType.Pointer:
172                         return StringifyTypeRef ((t as TypeSpecification).ElementType) + "*";
173                 case MetadataType.ByReference:
174                         return StringifyTypeRef ((t as TypeSpecification).ElementType) + "&";
175                 case MetadataType.Pinned:
176                         return StringifyTypeRef ((t as TypeSpecification).ElementType) + " pinned";
177                 case MetadataType.GenericInstance: {
178                         var sb = new StringBuilder ();
179                         var inst = (t as GenericInstanceType);
180                         sb.Append (StringifyTypeRef (inst.ElementType));
181                         sb.Append ("<");
182                         int aindex = 0;
183                         foreach (TypeReference arg in inst.GenericArguments) {
184                                 if (aindex > 0)
185                                         sb.Append (", ");
186                                 sb.Append (StringifyTypeRef (arg));
187                                 aindex ++;
188                         }
189                         sb.Append (">");
190                         return sb.ToString ();
191                 }
192                 case MetadataType.Var:
193                         return "!" + (t as GenericParameter).Position;
194                 case MetadataType.MVar:
195                         return "!!" + (t as GenericParameter).Position;
196                 case MetadataType.Sentinel:
197                         return "..., " + StringifyTypeRef ((t as SentinelType).ElementType);
198                 case MetadataType.RequiredModifier: {
199                         var mod = (t as RequiredModifierType);
200                         if (mod.ModifierType.MetadataType != MetadataType.Class)
201                                 throw new NotImplementedException ();
202                         var sb = new StringBuilder ();
203                         sb.Append (StringifyTypeRef (mod.ElementType));
204                         sb.Append (" modreq (");
205                         EmitScope (mod.ModifierType.Scope, sb);
206                         sb.Append (EscapeName (mod.ModifierType.FullName));
207                         sb.Append (")");
208                         return sb.ToString ();
209                 }
210                 default:
211                         throw new NotImplementedException ("" + t.MetadataType + " " + t.ToString ());
212                 }
213         }
214
215         // Same as StringifyTypeRef, but emit primitive types as [mscorlib]...
216         string StringifyTypeRefNoPrim (TypeReference t) {
217                 switch (t.MetadataType) {
218                 case MetadataType.Void:
219                 case MetadataType.Boolean:
220                 case MetadataType.Char:
221                 case MetadataType.SByte:
222                 case MetadataType.Byte:
223                 case MetadataType.Int16:
224                 case MetadataType.UInt16:
225                 case MetadataType.Int32:
226                 case MetadataType.UInt32:
227                 case MetadataType.Int64:
228                 case MetadataType.UInt64:
229                 case MetadataType.Single:
230                 case MetadataType.Double:
231                 case MetadataType.String:
232                 case MetadataType.IntPtr:
233                 case MetadataType.UIntPtr:
234                 case MetadataType.TypedByReference:
235                         return "[mscorlib]" + t.FullName;
236                 default:
237                         return StringifyTypeRef (t);
238                 }
239         }
240
241         string StringifyMethodRef (MethodReference method) {
242                 var sb = new StringBuilder ();
243                 if (method.CallingConvention == MethodCallingConvention.VarArg)
244                         sb.Append ("vararg ");
245                 if (method.HasThis)
246                         sb.Append ("instance ");
247                 sb.Append (StringifyTypeRef (method.ReturnType));
248                 sb.Append (' ');
249                 sb.Append (StringifyTypeRefNoPrim (method.DeclaringType));
250                 sb.Append ("::");
251                 sb.Append (EscapeName (method.Name));
252                 if (method is GenericInstanceMethod) {
253                         sb.Append ("<");
254                         int idx = 0;
255                         foreach (var gpar in (method as GenericInstanceMethod).GenericArguments) {
256                                 if (idx > 0)
257                                         sb.Append (", ");
258                                 sb.Append (StringifyTypeRef (gpar));
259                                 idx ++;
260                         }
261                         sb.Append (">");
262                 }
263                 sb.Append ('(');
264                 int par_index = 0;
265                 foreach (ParameterReference par in method.Parameters) {
266                         if (par_index > 0)
267                                 sb.Append (", ");
268                         sb.Append (StringifyTypeRef (par.ParameterType));
269                         par_index ++;
270                 }
271                 sb.Append (")");
272                 return sb.ToString ();
273         }
274
275         string StringifyFieldRef (FieldReference field) {
276                 var sb = new StringBuilder ();
277                 sb.Append (StringifyTypeRef (field.FieldType));
278                 sb.Append (' ');
279                 sb.Append (StringifyTypeRefNoPrim (field.DeclaringType));
280                 sb.Append ("::");
281                 sb.Append (EscapeName (field.Name));
282                 return sb.ToString ();
283         }
284
285         void WriteBlob (byte[] blob) {
286                 int idx = 0;
287                 while (idx < blob.Length) {
288                         int len = idx + 16 < blob.Length ? 16 : blob.Length - idx;
289                         var sb = new StringBuilder ();
290                         var sb2 = new StringBuilder ();
291                         for (int i = idx; i < idx + len; ++i) {
292                                 sb.Append (String.Format ("{0:X2} ", blob [i]));
293                                 if (Char.IsLetterOrDigit ((char)blob [i]))
294                                         sb2.Append ((char)blob [i]);
295                                 else
296                                         sb2.Append ('.');
297                         }
298                         for (int i = 0; i < 16 - len; ++i)
299                                 sb.Append ("   ");
300                         if (len < 16 || idx + 16 == blob.Length)
301                                 sb.Append (')');
302                         else
303                                 sb.Append (' ');
304                         WriteLine (String.Format ("{0} // {1}", sb.ToString (), sb2.ToString ()));
305                         idx += 16;
306                 }
307         }
308
309         string Map (Dictionary <uint, string> map, uint val) {
310                 string s;
311
312                 if (map.TryGetValue (val, out s))
313                         return s;
314                 else
315                         throw new NotImplementedException ("Value '" + val + "' not supported.");
316         }
317
318         string MapFlags (Dictionary <uint, string> map, uint val) {
319                 var sb = new StringBuilder ();
320                 foreach (var flag in map.Keys)
321                         if ((val & flag) != 0)
322                                 sb.Append (map [flag]);
323                 return sb.ToString ();
324         }
325
326         void EmitAssemblyReferences () {
327                 foreach (var aname in main.AssemblyReferences) {
328                         os.WriteLine (".assembly extern " + EscapeName (aname.Name));
329                         os.WriteLine ("{");
330                         indent ++;
331                         Version v = aname.Version;
332                         WriteLine (String.Format (".ver {0}:{1}:{2}:{3}", v.Major, v.Minor, v.Build, v.Revision));
333                         byte [] token = aname.PublicKeyToken;
334                         if (token.Length > 0) {
335                                 StringBuilder sb = new StringBuilder ();
336                                 StringBuilder sb2 = new StringBuilder ();
337                                 for (int i = 0; i < token.Length; ++i) {
338                                         if (i > 0)
339                                                 sb.Append (" ");
340                                         sb.Append (String.Format ("{0:X2}", token [i]));
341                                         if (Char.IsLetterOrDigit ((char)token [i]))
342                                                 sb2.Append ((char)token [i]);
343                                         else
344                                                 sb2.Append ('.');
345                                 }
346                                 WriteLine (String.Format (".publickeytoken = ({0}) // {1}", sb, sb2));
347                         }
348                         indent --;
349                         WriteLine ("}");
350                 }
351         }
352
353         void EmitCattrs (ICustomAttributeProvider prov) {
354                 foreach (var cattr in prov.CustomAttributes) {
355                         WriteLine (String.Format (".custom {0} = (", StringifyMethodRef (cattr.Constructor)));
356                         indent += 3;
357                         byte[] blob = cattr.GetBlob ();
358                         WriteBlob (blob);
359                         indent -= 3;
360                 }
361         }
362
363         void EmitSecDeclarations (ISecurityDeclarationProvider prov) {
364                 foreach (var sec in prov.SecurityDeclarations) {
365                         string act_str = null;
366                         if (!sec_action_to_string.TryGetValue (sec.Action, out act_str))
367                                 throw new NotImplementedException (sec.Action.ToString ());
368                         WriteLine (".permissionset " + act_str + " = (");
369                         WriteBlob (sec.GetBlob ());
370                 }
371         }
372
373         void EmitAssembly () {
374                 AssemblyNameDefinition aname = ad.Name;
375
376                 WriteLine (".assembly " + EscapeName (aname.Name));
377                 WriteLine ("{");
378                 indent ++;
379                 EmitCattrs (ad);
380                 EmitSecDeclarations (ad);
381                 WriteLine (String.Format (".hash algorithm 0x{0:X8}", (int)aname.HashAlgorithm));
382                 Version v = aname.Version;
383                 WriteLine (String.Format (".ver {0}:{1}:{2}:{3}", v.Major, v.Minor, v.Build, v.Revision));
384                 byte[] token = aname.PublicKey;
385                 if (token != null && token.Length > 0) {
386                         StringBuilder sb = new StringBuilder ();
387                         StringBuilder sb2 = new StringBuilder ();
388                         for (int i = 0; i < token.Length; ++i) {
389                                 if (i > 0)
390                                         sb.Append (" ");
391                                 sb.Append (String.Format ("{0:X2}", token [i]));
392                                 if (Char.IsLetterOrDigit ((char)token [i]))
393                                         sb2.Append ((char)token [i]);
394                                 else
395                                         sb2.Append ('.');
396                         }
397                         WriteLine (String.Format (".publickey = ({0}) // {1}", sb, sb2));
398                 }
399                 indent --;
400                 WriteLine ("}");
401         }
402
403         void EmitModule () {
404                 WriteLine (".module " + EscapeName (main.Name) + " // GUID = " + "{" + main.Mvid.ToString ().ToUpper () + "}");
405                 EmitCattrs (main);
406         }
407
408         string StringifyTypeAttrs (TypeAttributes attrs) {
409                 var sb = new StringBuilder ();
410
411                 sb.Append (Map (type_sem_map, (uint)(attrs & TypeAttributes.ClassSemanticMask)));
412                 sb.Append (Map (type_access_map, (uint)(attrs & TypeAttributes.VisibilityMask)));
413                 sb.Append (Map (type_layout_map, (uint)(attrs & TypeAttributes.LayoutMask)));
414                 sb.Append (Map (type_string_format_map, (uint)(attrs & TypeAttributes.StringFormatMask)));
415                 sb.Append (MapFlags (type_flag_map, (uint)(attrs)));
416
417                 return sb.ToString ();
418         }
419
420         void EmitGenParams (IGenericParameterProvider prov, StringBuilder sb) {
421                 sb.Append ("<");
422                 int idx = 0;
423                 foreach (var gpar in prov.GenericParameters) {
424                         if (idx > 0)
425                                 sb.Append (", ");
426                         if (gpar.HasDefaultConstructorConstraint)
427                                 sb.Append (".ctor ");
428                         if (gpar.HasNotNullableValueTypeConstraint)
429                                 sb.Append ("valuetype ");
430                         if (gpar.HasReferenceTypeConstraint)
431                                 sb.Append ("class ");
432                         if (gpar.HasConstraints) {
433                                 int idx2 = 0;
434                                 sb.Append ("(");
435                                 foreach (var c in gpar.Constraints) {
436                                         if (idx2 > 0)
437                                                 sb.Append (", ");
438                                         sb.Append (StringifyTypeRef (c));
439                                         idx2 ++;
440                                 }
441                                 sb.Append (")");
442                         }
443                         sb.Append (EscapeName (gpar.Name));
444                         idx ++;
445                 }
446                 sb.Append (">");
447         }
448
449         void EmitGenParamCattrs (IGenericParameterProvider prov) {
450                 foreach (var gpar in prov.GenericParameters) {
451                         if (gpar.HasCustomAttributes) {
452                                 WriteLine (".param type " + gpar.Name);
453                                 EmitCattrs (gpar);
454                         }
455                 }
456         }
457
458         void EmitGlobals (TypeDefinition td) {
459                 foreach (var md in td.Methods)
460                         EmitMethod (md);
461         }
462
463         void EmitType (TypeDefinition td) {
464                 WriteLine ("");
465
466                 if (td.MetadataType != MetadataType.Class && td.MetadataType != MetadataType.ValueType)
467                         throw new NotImplementedException (td.MetadataType.ToString ());
468
469                 // FIXME: Group types by namespaces
470                 if (!td.IsNested && td.Namespace != null && td.Namespace != String.Empty) {
471                         WriteLine (".namespace " + EscapeName (td.Namespace));
472                         WriteLine ("{");
473                         indent ++;
474                 }
475
476                 var sb = new StringBuilder ();
477                 sb.Append (".class ");
478                 sb.Append (StringifyTypeAttrs (td.Attributes));
479                 sb.Append (EscapeName (td.Name));
480                 if (td.HasGenericParameters)
481                         EmitGenParams (td, sb);
482                 WriteLine (sb.ToString ());
483                 indent ++;
484                 if (td.BaseType != null)
485                         WriteLine ("extends " + StringifyTypeRef (td.BaseType));
486                 if (td.HasInterfaces) {
487                         int idx = 0;
488                         sb = new StringBuilder ();
489                         foreach (TypeReference t in td.Interfaces) {
490                                 if (idx > 0)
491                                         sb.Append (", ");
492                                 sb.Append (StringifyTypeRef (t));
493                                 idx ++;
494                         }
495                         WriteLine (String.Format ("implements {0}", sb.ToString ()));
496                 }
497                 indent --;
498                 WriteLine ("{");
499                 indent ++;
500                 if (td.PackingSize != -1)
501                         WriteLine (".pack " + td.PackingSize);
502                 if (td.ClassSize != -1)
503                         WriteLine (".size " + td.ClassSize);
504                 EmitCattrs (td);
505                 EmitGenParamCattrs (td);
506                 EmitSecDeclarations (td);
507                 foreach (var fd in td.Fields)
508                         EmitField (fd);
509                 foreach (var md in td.Methods)
510                         EmitMethod (md);
511                 foreach (var p in td.Properties)
512                         EmitProperty (p);
513                 foreach (var e in td.Events)
514                         EmitEvent (e);
515                 foreach (var t in td.NestedTypes)
516                         EmitType (t);
517                 indent --;
518                 WriteLine ("}");
519
520                 if (!td.IsNested && td.Namespace != null && td.Namespace != String.Empty) {
521                         WriteLine ("}");
522                         indent --;
523                 }
524         }
525
526         string StringifyFieldAttributes (FieldAttributes attrs) {
527                 var sb = new StringBuilder ();
528                 sb.Append (Map (field_access_map, (uint)(attrs & FieldAttributes.FieldAccessMask)));
529                 sb.Append (MapFlags (field_flag_map, (uint)(attrs)));
530                 return sb.ToString ();
531         }
532
533         void EmitField (FieldDefinition fd) {
534                 var sb = new StringBuilder ();
535                 sb.Append (".field ");
536                 if (fd.Offset != -1)
537                         sb.Append ("[" + fd.Offset + "] ");
538                 sb.Append (StringifyFieldAttributes (fd.Attributes));
539                 if (fd.HasMarshalInfo) {
540                         sb.Append (" ");
541                         sb.Append (StringifyMarshalInfo (fd.MarshalInfo));
542                 }
543                 sb.Append (" ");
544                 sb.Append (StringifyTypeRef (fd.FieldType));
545                 sb.Append (" ");
546                 sb.Append (EscapeName (fd.Name));
547                 if (fd.HasConstant)
548                         EmitConstant (fd.Constant, sb);
549                 if (fd.RVA != 0) {
550                         sb.Append (String.Format (" at D_{0:x8}", fd.RVA));
551                         fields_with_rva.Add (fd);
552                 }
553                 WriteLine (sb.ToString ());
554                 EmitCattrs (fd);
555         }
556
557         string StringifyMethodAttributes (MethodAttributes attrs) {
558                 var sb = new StringBuilder ();
559                 sb.Append (Map (method_access_map, (uint)(attrs & MethodAttributes.MemberAccessMask)));
560                 sb.Append (MapFlags (method_flag_map, (uint)(attrs)));
561                 return sb.ToString ();
562         }
563
564         string StringifyMethodImplAttributes (MethodImplAttributes attrs) {
565                 var sb = new StringBuilder ();
566                 sb.Append (Map (method_impl_map, (uint)(attrs & MethodImplAttributes.CodeTypeMask)));
567                 sb.Append (Map (method_managed_map, (uint)(attrs & MethodImplAttributes.ManagedMask)));
568                 sb.Append (MapFlags (method_impl_flag_map, (uint)(attrs)));
569
570                 return sb.ToString ();
571         }
572
573         string StringifyTypeNameReflection (TypeReference t) {
574                 if (t.MetadataType != MetadataType.Class)
575                         throw new NotImplementedException ();
576                 IMetadataScope s = t.Scope;
577                 if (!(s is ModuleDefinition))
578                         throw new NotImplementedException ();
579                 return t.FullName.Replace ("/", "+");
580         }
581
582         string StringifyMarshalInfo (MarshalInfo mi) {
583                 var sb = new StringBuilder ();
584
585                 sb.Append ("marshal (");
586
587                 string s = null;
588                 switch (mi.NativeType) {
589                 case NativeType.Array: {
590                         var ami = (mi as ArrayMarshalInfo);
591                         if (native_type_to_str.TryGetValue (ami.ElementType, out s)) {
592                                 sb.Append (s);
593                         }
594                         sb.Append ("[");
595                         //Console.WriteLine ("// XXX: " + ami.Size + " " + ami.SizeParameterIndex + " " + ami.SizeParameterMultiplier);
596
597                         /*
598                          * Comments in metadata.c:
599                          * So if (param_num == 0) && (num_elem > 0), then
600                          * elem_mult == 0 -> the array size is num_elem
601                          * elem_mult == 1 -> the array size is @param_num + num_elem
602                          */
603                         if (ami.Size != -1 && ami.Size != 0)
604                                 sb.Append (ami.Size.ToString ());
605                         if (ami.SizeParameterMultiplier != 0 && ami.SizeParameterIndex != -1)
606                                 sb.Append ("+" + ami.SizeParameterIndex.ToString ());
607                         sb.Append ("]");
608                         break;
609                 }
610                 case NativeType.FixedArray: {
611                         var ami = (mi as FixedArrayMarshalInfo);
612                         /*
613                         if (native_type_to_str.TryGetValue (ami.ElementType, out s)) {
614                                 sb.Append (s);
615                         }
616                         */
617                         sb.Append ("fixed array [" + ami.Size + "]");
618                         break;
619                 }
620                 case NativeType.FixedSysString: {
621                         var ami = (mi as FixedSysStringMarshalInfo);
622                         sb.Append ("fixed sysstring [" + ami.Size + "]");
623                         break;
624                 }
625                 case NativeType.SafeArray: {
626                         var sami = (mi as SafeArrayMarshalInfo);
627                         sb.Append ("safearray ");
628                         switch (sami.ElementType) {
629                         case VariantType.Variant:
630                                 sb.Append ("variant");
631                                 break;
632                         default:
633                                 throw new NotImplementedException ();
634                         }
635                         break;
636                 }
637                 case NativeType.CustomMarshaler: {
638                         var cmi = (mi as CustomMarshalInfo);
639
640                         if (cmi.Guid != Guid.Empty || cmi.UnmanagedType != String.Empty)
641                                 throw new NotImplementedException ();
642                         sb.Append ("custom (\"" + StringifyTypeNameReflection (cmi.ManagedType) + "\", \"" + EscapeString (cmi.Cookie) + "\")");
643                         break;
644                 }
645                 default:
646                         if (native_type_to_str.TryGetValue (mi.NativeType, out s))
647                                 sb.Append (s);
648                         else
649                                 throw new NotImplementedException (mi.NativeType.ToString ());
650                         break;
651                 }
652                 sb.Append (")");
653                 return sb.ToString ();
654         }
655
656         string StringifySignature (MethodDefinition md) {
657                 var sb = new StringBuilder ();
658                 int pindex = 0;
659                 foreach (var par in md.Parameters) {
660                         if (pindex > 0)
661                                 sb.Append (", ");
662                         if (par.IsIn)
663                                 sb.Append ("[in] ");
664                         if (par.IsOut)
665                                 sb.Append ("[out] ");
666                         if (par.IsOptional)
667                                 sb.Append ("[opt] ");
668                         sb.Append (StringifyTypeRef (par.ParameterType));
669                         if (par.HasMarshalInfo) {
670                                 sb.Append (" ");
671                                 sb.Append (StringifyMarshalInfo (par.MarshalInfo));
672                         }
673                         sb.Append (" ");
674                         sb.Append (EscapeName (par.Name));
675                         pindex ++;
676                 }
677
678                 return sb.ToString ();
679         }
680
681         string StringifyPInvokeAttrs (PInvokeAttributes attrs) {
682                 var sb = new StringBuilder ();
683                 sb.Append (Map (pinvoke_char_set_map, (uint)(attrs & PInvokeAttributes.CharSetMask)));
684                 sb.Append (Map (pinvoke_cconv_map, (uint)(attrs & PInvokeAttributes.CallConvMask)));
685                 sb.Append (MapFlags (pinvoke_flags_map, (uint)(attrs)));
686                 return sb.ToString ();
687         }               
688
689         string StringifyCallingConvention (MethodCallingConvention cconv) {
690                 switch (cconv) {
691                 case MethodCallingConvention.Default:
692                         return "default";
693                 case MethodCallingConvention.VarArg:
694                         return "vararg";
695                 default:
696                         throw new NotImplementedException (cconv.ToString ());
697                 }
698         }
699
700         void EmitMethod (MethodDefinition md) {
701                 int idx;
702
703                 WriteLine ();
704                 var pinvoke_sb = new StringBuilder ();
705                 if ((uint)(md.Attributes & MethodAttributes.PInvokeImpl) != 0) {
706                         var pinvoke = md.PInvokeInfo;
707                         pinvoke_sb.Append ("pinvokeimpl (\"" + pinvoke.Module.Name + "\" as \"" + pinvoke.EntryPoint + "\" " + StringifyPInvokeAttrs (pinvoke.Attributes) + " )");
708                 }
709                 WriteLine (String.Format (".method {0}{1}", StringifyMethodAttributes (md.Attributes), pinvoke_sb));
710
711                 var sb = new StringBuilder ();
712                 sb.Append ("       ");
713                 if (!md.IsStatic)
714                         sb.Append ("instance ");                
715                 // CallingConvention seems to be 32
716                 sb.Append (StringifyCallingConvention ((MethodCallingConvention)((uint)md.CallingConvention & 0xf)));
717                 sb.Append (" ");
718                 sb.Append (StringifyTypeRef (md.ReturnType));
719                 sb.Append (" ");
720                 if (md.MethodReturnType.HasMarshalInfo) {
721                         sb.Append (StringifyMarshalInfo (md.MethodReturnType.MarshalInfo));
722                         sb.Append (" ");
723                 }
724                 sb.Append (EscapeName (md.Name));
725                 if (md.HasGenericParameters)
726                         EmitGenParams (md, sb);
727                 WriteLine (String.Format ("{0} ({1}) {2}", sb, StringifySignature (md), StringifyMethodImplAttributes (md.ImplAttributes)));
728                 WriteLine ("{");
729                 indent ++;
730                 foreach (var ov in md.Overrides)
731                         WriteLine (".override method " + StringifyMethodRef (ov));
732                 EmitCattrs (md);
733                 EmitGenParamCattrs (md);
734                 EmitSecDeclarations (md);
735                 idx = 0;
736                 foreach (var par in md.Parameters) {
737                         if (par.HasCustomAttributes) {
738                                 WriteLine (".param [" + (idx + 1) + "]");
739                                 EmitCattrs (par);
740                         }
741                         if (par.HasConstant) {
742                                 sb = new StringBuilder ();
743                                 EmitConstant (par.Constant, sb);
744                                 WriteLine (".param [" + (idx + 1) + "]" + sb);
745                         }
746                         idx ++;
747                 }
748                 // FIXME: Print RVA, code size
749                 if (md == main.EntryPoint)
750                         WriteLine (".entrypoint");
751                 if (md.HasBody) {
752                         MethodBody body = md.Body;
753                         WriteLine (".maxstack " + body.MaxStackSize);
754                         if (body.InitLocals)
755                                 WriteLine (".locals init (");
756                         else
757                                 WriteLine (".locals (");
758                         indent ++;
759                         int vindex = 0;
760                         foreach (var v in body.Variables) {
761                                 WriteLine (StringifyTypeRef (v.VariableType) + " " + (v.Name == "" ? "V_" + v.Index : v.Name) + (vindex + 1 < body.Variables.Count ? ", " : ""));
762                                 vindex ++;
763                         }
764                         indent --;
765                         WriteLine (")");
766
767                         List<ExceptionHandler> handlers = body.ExceptionHandlers.ToList ();
768                         List<ExceptionHandler> reverse_handlers = body.ExceptionHandlers.Reverse ().ToList ();
769
770                         var trys = new Dictionary<ExceptionHandler, bool> ();
771                         if (handlers.Count > 0)
772                                 trys [handlers [0]] = true;
773                         for (int i = 1; i < handlers.Count; ++i) {
774                                 trys [handlers [i]] = true;
775                                 for (int j = 0; j < i; ++j) {
776                                         if (handlers [i].TryStart == handlers [j].TryStart && handlers [i].TryEnd == handlers [j].TryEnd) {
777                                                 trys [handlers [i]] = false;
778                                                 break;
779                                         }
780                                 }
781                         }
782
783                         idx = 0;
784                         var handler_to_idx = new Dictionary<ExceptionHandler, int> ();
785                         foreach (ExceptionHandler eh in body.ExceptionHandlers) {
786                                 handler_to_idx [eh] = idx;
787                                 idx ++;
788                         }
789
790                         foreach (var ins in body.Instructions) {
791                                 foreach (var eh in handlers) {
792                                         if (eh.TryEnd == ins && trys [eh]) {
793                                                 indent --;
794                                                 WriteLine ("} // end try " + handler_to_idx [eh]);
795                                         }
796
797                                         if (eh.HandlerEnd == ins) {
798                                                 indent --;
799                                                 WriteLine ("} // end handler " + handler_to_idx [eh]);
800                                         }
801                                 }                       
802
803                                 foreach (var eh in reverse_handlers) {
804                                         if (eh.TryStart == ins && trys [eh]) {
805                                                 WriteLine (".try { // " + handler_to_idx [eh]);
806                                                 indent ++;
807                                         }
808                                         if (eh.HandlerStart == ins) {
809                                                 string type_str = null;
810                                                 switch (eh.HandlerType) {
811                                                 case ExceptionHandlerType.Catch:
812                                                         type_str = "catch";
813                                                         break;
814                                                 case ExceptionHandlerType.Finally:
815                                                         type_str = "finally";
816                                                         break;
817                                                 default:
818                                                         throw new NotImplementedException (eh.HandlerType.ToString ());
819                                                 }
820                                                 if (eh.CatchType == null)
821                                                         WriteLine (type_str + " { // " + handler_to_idx [eh]);
822                                                 else
823                                                         WriteLine (type_str + " " + StringifyTypeRef (eh.CatchType) + " { // " + handler_to_idx [eh]);
824                                                 indent ++;
825                                         }
826                                 }
827
828                                 WriteLine (StringifyIns (ins));
829                         }
830                 }
831                 indent --;
832                 WriteLine ("}");
833         }
834
835         // Based on Instruction:ToString ()
836         public string StringifyIns (Instruction ins) {
837                 var sb = new StringBuilder ();
838
839                 AppendLabel (sb, ins);
840                 sb.Append (':');
841                 sb.Append ("  ");
842                 sb.Append (ins.OpCode.Name);
843
844                 if (ins.Operand == null)
845                         return sb.ToString ();
846
847                 sb.Append (' ');
848
849                 object operand = ins.Operand;
850                 switch (ins.OpCode.OperandType) {
851                 case OperandType.ShortInlineBrTarget:
852                 case OperandType.InlineBrTarget:
853                         AppendLabel (sb, (Instruction) operand);
854                         break;
855                 case OperandType.InlineSwitch:
856                         var labels = (Instruction []) operand;
857                         sb.Append ("(");
858                         for (int i = 0; i < labels.Length; i++) {
859                                 if (i > 0)
860                                         sb.Append (',');
861
862                                 AppendLabel (sb, labels [i]);
863                         }
864                         sb.Append (")");
865                         break;
866                         case OperandType.InlineString:
867                                 sb.Append ('\"');
868                                 sb.Append (EscapeString ((string)operand));
869                                 sb.Append ('\"');
870                                 break;
871                 default:
872                         if (operand is MethodReference) {
873                                 if (ins.OpCode == OpCodes.Ldtoken)
874                                         sb.Append ("method ");
875                                 sb.Append (StringifyMethodRef ((MethodReference)operand));
876                         } else if (operand is TypeReference)
877                                 sb.Append (StringifyTypeRef ((TypeReference)operand));
878                         else if (operand is VariableDefinition)
879                                 sb.Append (operand.ToString ());
880                         else if (operand is FieldReference) {
881                                 if (ins.OpCode == OpCodes.Ldtoken)
882                                         sb.Append ("field ");
883                                 sb.Append (StringifyFieldRef ((FieldReference)operand));
884                         } else if (operand is ParameterDefinition) {
885                                 var pd = (operand as ParameterDefinition);
886                                 sb.Append (pd.Index + (pd.Method.HasThis ? 1 : 0));
887                         }
888                         else {
889                                 EmitConstantOperand (operand, sb);
890                         }
891                         break;
892                         }
893
894                 return sb.ToString ();
895         }
896
897         static void AppendLabel (StringBuilder builder, Instruction instruction) {
898                 builder.Append ("IL_");
899                 builder.Append (instruction.Offset.ToString ("x4"));
900         }
901
902         void EmitProperty (PropertyDefinition p) {
903                 // FIXME: attributes
904
905                 var sb = new StringBuilder ();
906                 sb.Append (".property ");
907                 if (p.HasThis)
908                         sb.Append ("instance ");
909                 sb.Append (StringifyTypeRef (p.PropertyType));
910                 sb.Append (" ");
911                 sb.Append (EscapeName (p.Name));
912                 sb.Append ("(");
913                 int idx = 0;
914                 foreach (var par in p.Parameters) {
915                         if (idx > 0)
916                                 sb.Append (", ");
917                         sb.Append (StringifyTypeRef (par.ParameterType));
918                         idx ++;
919                 }
920                 sb.Append (")");
921                 WriteLine (sb.ToString ());
922                 WriteLine ("{");
923                 indent ++;
924                 EmitCattrs (p);
925                 if (p.SetMethod != null)
926                         WriteLine (".set " + StringifyMethodRef (p.SetMethod));
927                 if (p.GetMethod != null)
928                         WriteLine (".get " + StringifyMethodRef (p.GetMethod));
929                 if (p.HasOtherMethods)
930                         throw new NotImplementedException ();
931                 indent --;
932                 WriteLine ("}");
933         }
934
935         void EmitEvent (EventDefinition e) {
936                 WriteLine (".event " + StringifyTypeRef (e.EventType) + " " + EscapeName (e.Name));
937                 WriteLine ("{");
938                 indent ++;
939                 if (e.AddMethod != null)
940                         WriteLine (".addon " + StringifyMethodRef (e.AddMethod));
941                 if (e.RemoveMethod != null)
942                         WriteLine (".removeon " + StringifyMethodRef (e.RemoveMethod));
943                 foreach (var m in e.OtherMethods)
944                         WriteLine (".other " + StringifyMethodRef (m));
945                 indent --;
946                 WriteLine ("}");
947         }
948
949         void EmitData () {
950                 foreach (var fd in fields_with_rva) {
951                         WriteLine (String.Format (".data D_{0:x8} = bytearray (", fd.RVA));
952                         WriteBlob (fd.InitialValue);
953                 }
954         }
955
956         void EmitConstantOperand (object operand, StringBuilder sb) {
957                 if (operand is double) {
958                         double d = (double)operand;
959                         // FIXME:
960                         //if (Double.IsNaN (d) || Double.IsInfinity (d)) {
961                         {
962                                 byte[] b = DataConverter.GetBytesLE (d);
963                                 sb.Append ("(");
964                                 int index = 0;
965                                 for (int i = 0; i < b.Length; ++i) {
966                                         if (index > 0)
967                                                 sb.Append (" ");
968                                         sb.Append (String.Format ("{0:x2}", b [i]));
969                                         index ++;
970                                 }
971                                 sb.Append (")");
972                         }
973                 } else if (operand is float) {
974                         float d = (float)operand;
975                         // FIXME:
976                         //if (Single.IsNaN (d) || Single.IsInfinity (d)) {
977                         {
978                                 byte[] b = DataConverter.GetBytesLE (d);
979                                 sb.Append ("(");
980                                 int index = 0;
981                                 for (int i = 0; i < b.Length; ++i) {
982                                         if (index > 0)
983                                                 sb.Append (" ");
984                                         sb.Append (String.Format ("{0:x2}", b [i]));
985                                         index ++;
986                                 }
987                                 sb.Append (")");
988                         }
989                 } else if (operand.GetType ().Assembly == typeof (int).Assembly)
990                         sb.Append (operand.ToString ());
991                 else
992                         throw new NotImplementedException (operand.GetType ().ToString ());
993         }
994
995         void EmitConstant (object o, StringBuilder sb) {
996                 if (o is byte)
997                         sb.Append (String.Format (" = int8(0x{0:x2})", (byte)o));
998                 else if (o is sbyte)
999                         sb.Append (String.Format (" = int8(0x{0:x2})", (sbyte)o));
1000                 else if (o is short)
1001                         sb.Append (String.Format (" = int16(0x{0:x4})", (short)o));
1002                 else if (o is ushort)
1003                         sb.Append (String.Format (" = int16(0x{0:x4})", (ushort)o));
1004                 else if (o is int)
1005                         sb.Append (String.Format (" = int32(0x{0:x8})", (int)o));
1006                 else if (o is uint)
1007                         sb.Append (String.Format (" = int32(0x{0:x8})", (uint)o));
1008                 else if (o is long)
1009                         sb.Append (String.Format (" = int64(0x{0:x8})", (long)o));
1010                 else if (o is ulong)
1011                         sb.Append (String.Format (" = int64(0x{0:x8})", (ulong)o));
1012                 else if (o is string)
1013                         sb.Append (String.Format (" = \"{0}\"", EscapeString ((string)o)));
1014                 else if (o is bool)
1015                         sb.Append (String.Format (" = bool({0})", (bool)o ? "true" : " false"));
1016                 else if (o is char)
1017                         sb.Append (String.Format (" = char(0x{0:x4})", (int)(char)o));
1018                 else if (o is double)
1019                         // FIXME:
1020                         sb.Append (String.Format (" = float64({0:f})", (double)o));
1021                 else if (o is float)
1022                         // FIXME:
1023                         sb.Append (String.Format (" = float32({0:f})", (float)o));
1024                 else if (o == null)
1025                         sb.Append ("= nullref");
1026                 else
1027                         throw new NotImplementedException ("" + o.GetType ().ToString () + " " + o.ToString ());
1028         }
1029 }