Merge pull request #3040 from xmcclure/debugger-step-recursive
[mono.git] / mcs / tools / cil-strip / Mono.Cecil.Signatures / SignatureWriter.cs
1 //
2 // SignatureWriter.cs
3 //
4 // Author:
5 //   Jb Evain (jbevain@gmail.com)
6 //
7 // (C) 2005 - 2007 Jb Evain
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 //
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28
29 namespace Mono.Cecil.Signatures {
30
31         using System;
32         using System.Text;
33
34         using Mono.Cecil;
35         using Mono.Cecil.Binary;
36         using Mono.Cecil.Metadata;
37
38         internal sealed class SignatureWriter : BaseSignatureVisitor {
39
40                 MetadataWriter m_mdWriter;
41                 MemoryBinaryWriter m_sigWriter;
42
43                 public SignatureWriter (MetadataWriter mdWriter)
44                 {
45                         m_mdWriter = mdWriter;
46                         m_sigWriter = new MemoryBinaryWriter ();
47                 }
48
49                 uint GetPointer ()
50                 {
51                         return m_mdWriter.AddBlob (m_sigWriter.ToArray ());
52                 }
53
54                 public uint AddMethodDefSig (MethodDefSig methSig)
55                 {
56                         return AddSignature (methSig);
57                 }
58
59                 public uint AddMethodRefSig (MethodRefSig methSig)
60                 {
61                         return AddSignature (methSig);
62                 }
63
64                 public uint AddPropertySig (PropertySig ps)
65                 {
66                         return AddSignature (ps);
67                 }
68
69                 public uint AddFieldSig (FieldSig fSig)
70                 {
71                         return AddSignature (fSig);
72                 }
73
74                 public uint AddLocalVarSig (LocalVarSig lvs)
75                 {
76                         return AddSignature (lvs);
77                 }
78
79                 uint AddSignature (Signature s)
80                 {
81                         m_sigWriter.Empty ();
82                         s.Accept (this);
83                         return GetPointer ();
84                 }
85
86                 public uint AddTypeSpec (TypeSpec ts)
87                 {
88                         m_sigWriter.Empty ();
89                         Write (ts);
90                         return GetPointer ();
91                 }
92
93                 public uint AddMethodSpec (MethodSpec ms)
94                 {
95                         m_sigWriter.Empty ();
96                         Write (ms);
97                         return GetPointer ();
98                 }
99
100                 public uint AddMarshalSig (MarshalSig ms)
101                 {
102                         m_sigWriter.Empty ();
103                         Write (ms);
104                         return GetPointer ();
105                 }
106
107                 public uint AddCustomAttribute (CustomAttrib ca, MethodReference ctor)
108                 {
109                         CompressCustomAttribute (ca, ctor, m_sigWriter);
110                         return GetPointer ();
111                 }
112
113                 public byte [] CompressCustomAttribute (CustomAttrib ca, MethodReference ctor)
114                 {
115                         MemoryBinaryWriter writer = new MemoryBinaryWriter ();
116                         CompressCustomAttribute (ca, ctor, writer);
117                         return writer.ToArray ();
118                 }
119
120                 public byte [] CompressFieldSig (FieldSig field)
121                 {
122                         m_sigWriter.Empty ();
123                         VisitFieldSig (field);
124                         return m_sigWriter.ToArray ();
125                 }
126
127                 public byte [] CompressLocalVar (LocalVarSig.LocalVariable var)
128                 {
129                         m_sigWriter.Empty ();
130                         Write (var);
131                         return m_sigWriter.ToArray ();
132                 }
133
134                 void CompressCustomAttribute (CustomAttrib ca, MethodReference ctor, MemoryBinaryWriter writer)
135                 {
136                         m_sigWriter.Empty ();
137                         Write (ca, ctor, writer);
138                 }
139
140                 public override void VisitMethodDefSig (MethodDefSig methodDef)
141                 {
142                         m_sigWriter.Write (methodDef.CallingConvention);
143                         if (methodDef.GenericParameterCount > 0)
144                                 Write (methodDef.GenericParameterCount);
145                         Write (methodDef.ParamCount);
146                         Write (methodDef.RetType);
147                         Write (methodDef.Parameters, methodDef.Sentinel);
148                 }
149
150                 public override void VisitMethodRefSig (MethodRefSig methodRef)
151                 {
152                         m_sigWriter.Write (methodRef.CallingConvention);
153                         Write (methodRef.ParamCount);
154                         Write (methodRef.RetType);
155                         Write (methodRef.Parameters, methodRef.Sentinel);
156                 }
157
158                 public override void VisitFieldSig (FieldSig field)
159                 {
160                         m_sigWriter.Write (field.CallingConvention);
161                         Write (field.CustomMods);
162                         Write (field.Type);
163                 }
164
165                 public override void VisitPropertySig (PropertySig property)
166                 {
167                         m_sigWriter.Write (property.CallingConvention);
168                         Write (property.ParamCount);
169                         Write (property.CustomMods);
170                         Write (property.Type);
171                         Write (property.Parameters);
172                 }
173
174                 public override void VisitLocalVarSig (LocalVarSig localvar)
175                 {
176                         m_sigWriter.Write (localvar.CallingConvention);
177                         Write (localvar.Count);
178                         Write (localvar.LocalVariables);
179                 }
180
181                 void Write (LocalVarSig.LocalVariable [] vars)
182                 {
183                         foreach (LocalVarSig.LocalVariable var in vars)
184                                 Write (var);
185                 }
186
187                 void Write (LocalVarSig.LocalVariable var)
188                 {
189                         Write (var.CustomMods);
190                         if ((var.Constraint & Constraint.Pinned) != 0)
191                                 Write (ElementType.Pinned);
192                         if (var.ByRef)
193                                 Write (ElementType.ByRef);
194                         Write (var.Type);
195                 }
196
197                 void Write (RetType retType)
198                 {
199                         Write (retType.CustomMods);
200                         if (retType.Void)
201                                 Write (ElementType.Void);
202                         else if (retType.TypedByRef)
203                                 Write (ElementType.TypedByRef);
204                         else if (retType.ByRef) {
205                                 Write (ElementType.ByRef);
206                                 Write (retType.Type);
207                         } else
208                                 Write (retType.Type);
209                 }
210
211                 void Write (Param [] parameters, int sentinel)
212                 {
213                         for (int i = 0; i < parameters.Length; i++) {
214                                 if (i == sentinel)
215                                         Write (ElementType.Sentinel);
216
217                                 Write (parameters [i]);
218                         }
219                 }
220
221                 void Write (Param [] parameters)
222                 {
223                         foreach (Param p in parameters)
224                                 Write (p);
225                 }
226
227                 void Write (ElementType et)
228                 {
229                         Write ((int) et);
230                 }
231
232                 void Write (SigType t)
233                 {
234                         Write ((int) t.ElementType);
235
236                         switch (t.ElementType) {
237                         case ElementType.ValueType :
238                                 Write ((int) Utilities.CompressMetadataToken (
239                                                 CodedIndex.TypeDefOrRef, ((VALUETYPE) t).Type));
240                                 break;
241                         case ElementType.Class :
242                                 Write ((int) Utilities.CompressMetadataToken (
243                                                 CodedIndex.TypeDefOrRef, ((CLASS) t).Type));
244                                 break;
245                         case ElementType.Ptr :
246                                 PTR p = (PTR) t;
247                                 if (p.Void)
248                                         Write (ElementType.Void);
249                                 else {
250                                         Write (p.CustomMods);
251                                         Write (p.PtrType);
252                                 }
253                                 break;
254                         case ElementType.FnPtr :
255                                 FNPTR fp = (FNPTR) t;
256                                 if (fp.Method is MethodRefSig)
257                                         (fp.Method as MethodRefSig).Accept (this);
258                                 else
259                                         (fp.Method as MethodDefSig).Accept (this);
260                                 break;
261                         case ElementType.Array :
262                                 ARRAY ary = (ARRAY) t;
263                                 Write (ary.CustomMods);
264                                 ArrayShape shape = ary.Shape;
265                                 Write (ary.Type);
266                                 Write (shape.Rank);
267                                 Write (shape.NumSizes);
268                                 foreach (int size in shape.Sizes)
269                                         Write (size);
270                                 Write (shape.NumLoBounds);
271                                 foreach (int loBound in shape.LoBounds)
272                                         Write (loBound);
273                                 break;
274                         case ElementType.SzArray :
275                                 SZARRAY sa = (SZARRAY) t;
276                                 Write (sa.CustomMods);
277                                 Write (sa.Type);
278                                 break;
279                         case ElementType.Var :
280                                 Write (((VAR) t).Index);
281                                 break;
282                         case ElementType.MVar :
283                                 Write (((MVAR) t).Index);
284                                 break;
285                         case ElementType.GenericInst :
286                                 GENERICINST gi = t as GENERICINST;
287                                 Write (gi.ValueType ? ElementType.ValueType : ElementType.Class);
288                                 Write ((int) Utilities.CompressMetadataToken (
289                                                 CodedIndex.TypeDefOrRef, gi.Type));
290                                 Write (gi.Signature);
291                                 break;
292                         }
293                 }
294
295                 void Write (TypeSpec ts)
296                 {
297                         Write (ts.CustomMods);
298                         Write (ts.Type);
299                 }
300
301                 void Write (MethodSpec ms)
302                 {
303                         Write (0x0a);
304                         Write (ms.Signature);
305                 }
306
307                 void Write (GenericInstSignature gis)
308                 {
309                         Write (gis.Arity);
310                         for (int i = 0; i < gis.Arity; i++)
311                                 Write (gis.Types [i]);
312                 }
313
314                 void Write (GenericArg arg)
315                 {
316                         Write (arg.CustomMods);
317                         Write (arg.Type);
318                 }
319
320                 void Write (Param p)
321                 {
322                         Write (p.CustomMods);
323                         if (p.TypedByRef)
324                                 Write (ElementType.TypedByRef);
325                         else if (p.ByRef) {
326                                 Write (ElementType.ByRef);
327                                 Write (p.Type);
328                         } else
329                                 Write (p.Type);
330                 }
331
332                 void Write (CustomMod [] customMods)
333                 {
334                         foreach (CustomMod cm in customMods)
335                                 Write (cm);
336                 }
337
338                 void Write (CustomMod cm)
339                 {
340                         switch (cm.CMOD) {
341                         case CustomMod.CMODType.OPT :
342                                 Write (ElementType.CModOpt);
343                                 break;
344                         case CustomMod.CMODType.REQD :
345                                 Write (ElementType.CModReqD);
346                                 break;
347                         }
348
349                         Write ((int) Utilities.CompressMetadataToken (
350                                         CodedIndex.TypeDefOrRef, cm.TypeDefOrRef));
351                 }
352
353                 void Write (MarshalSig ms)
354                 {
355                         Write ((int) ms.NativeInstrinsic);
356                         switch (ms.NativeInstrinsic) {
357                         case NativeType.ARRAY :
358                                 MarshalSig.Array ar = (MarshalSig.Array) ms.Spec;
359                                 Write ((int) ar.ArrayElemType);
360                                 if (ar.ParamNum != -1)
361                                         Write (ar.ParamNum);
362                                 if (ar.NumElem != -1)
363                                         Write (ar.NumElem);
364                                 if (ar.ElemMult != -1)
365                                         Write (ar.ElemMult);
366                                 break;
367                         case NativeType.CUSTOMMARSHALER :
368                                 MarshalSig.CustomMarshaler cm = (MarshalSig.CustomMarshaler) ms.Spec;
369                                 Write (cm.Guid);
370                                 Write (cm.UnmanagedType);
371                                 Write (cm.ManagedType);
372                                 Write (cm.Cookie);
373                                 break;
374                         case NativeType.FIXEDARRAY :
375                                 MarshalSig.FixedArray fa = (MarshalSig.FixedArray) ms.Spec;
376                                 Write (fa.NumElem);
377                                 if (fa.ArrayElemType != NativeType.NONE)
378                                         Write ((int) fa.ArrayElemType);
379                                 break;
380                         case NativeType.SAFEARRAY :
381                                 Write ((int) ((MarshalSig.SafeArray) ms.Spec).ArrayElemType);
382                                 break;
383                         case NativeType.FIXEDSYSSTRING :
384                                 Write (((MarshalSig.FixedSysString) ms.Spec).Size);
385                                 break;
386                         }
387                 }
388
389                 void Write (CustomAttrib ca, MethodReference ctor, MemoryBinaryWriter writer)
390                 {
391                         if (ca == null)
392                                 return;
393
394                         if (ca.Prolog != CustomAttrib.StdProlog)
395                                 return;
396
397                         writer.Write (ca.Prolog);
398
399                         for (int i = 0; i < ctor.Parameters.Count; i++)
400                                 Write (ca.FixedArgs [i], writer);
401
402                         writer.Write (ca.NumNamed);
403
404                         for (int i = 0; i < ca.NumNamed; i++)
405                                 Write (ca.NamedArgs [i], writer);
406                 }
407
408                 void Write (CustomAttrib.FixedArg fa, MemoryBinaryWriter writer)
409                 {
410                         if (fa.SzArray)
411                                 writer.Write (fa.NumElem);
412
413                         foreach (CustomAttrib.Elem elem in fa.Elems)
414                                 Write (elem, writer);
415                 }
416
417                 static string GetEnumFullName (TypeReference type)
418                 {
419                         string fullname = type.FullName;
420
421                         if (type.IsNested)
422                                 fullname = fullname.Replace ('/', '+');
423
424                         if (type is TypeDefinition)
425                                 return fullname;
426
427                         return string.Concat (fullname, ", ", type.Module.Assembly.Name.FullName);
428                 }
429
430                 void Write (CustomAttrib.NamedArg na, MemoryBinaryWriter writer)
431                 {
432                         if (na.Field)
433                                 writer.Write ((byte) 0x53);
434                         else if (na.Property)
435                                 writer.Write ((byte) 0x54);
436                         else
437                                 throw new MetadataFormatException ("Unknown kind of namedarg");
438
439                         if (na.FieldOrPropType == ElementType.Class)
440                                 na.FieldOrPropType = ElementType.Enum;
441
442                         if (na.FixedArg.SzArray)
443                                 writer.Write ((byte) ElementType.SzArray);
444
445                         if (na.FieldOrPropType == ElementType.Object)
446                                 writer.Write ((byte) ElementType.Boxed);
447                         else
448                                 writer.Write ((byte) na.FieldOrPropType);
449
450                         if (na.FieldOrPropType == ElementType.Enum)
451                                 Write (GetEnumFullName (na.FixedArg.Elems [0].ElemType));
452
453                         Write (na.FieldOrPropName);
454
455                         Write (na.FixedArg, writer);
456                 }
457
458                 static ElementType GetElementTypeFromTypeCode (TypeCode tc)
459                 {
460                         switch (tc) {
461                         case TypeCode.Byte:
462                                 return ElementType.U1;
463                         case TypeCode.SByte:
464                                 return ElementType.I1;
465                         case TypeCode.Int16:
466                                 return ElementType.I2;
467                         case TypeCode.UInt16:
468                                 return ElementType.U2;
469                         case TypeCode.Int32:
470                                 return ElementType.I4;
471                         case TypeCode.UInt32:
472                                 return ElementType.U4;
473                         case TypeCode.Int64:
474                                 return ElementType.I8;
475                         case TypeCode.UInt64:
476                                 return ElementType.U8;
477                         default:
478                                 throw new ArgumentException ("tc");
479                         }
480                 }
481
482                 void Write (CustomAttrib.Elem elem, MemoryBinaryWriter writer)
483                 {
484                         if (elem.String)
485                                 elem.FieldOrPropType = ElementType.String;
486                         else if (elem.Type)
487                                 elem.FieldOrPropType = ElementType.Type;
488
489                         if (elem.FieldOrPropType == ElementType.Class) // an enum in fact
490                                 elem.FieldOrPropType = GetElementTypeFromTypeCode (Type.GetTypeCode (elem.Value.GetType ()));
491
492                         if (elem.BoxedValueType)
493                                 Write (elem.FieldOrPropType);
494
495                         switch (elem.FieldOrPropType) {
496                         case ElementType.Boolean :
497                                 writer.Write ((byte) ((bool) elem.Value ? 1 : 0));
498                                 break;
499                         case ElementType.Char :
500                                 writer.Write ((ushort) (char) elem.Value);
501                                 break;
502                         case ElementType.R4 :
503                                 writer.Write ((float) elem.Value);
504                                 break;
505                         case ElementType.R8 :
506                                 writer.Write ((double) elem.Value);
507                                 break;
508                         case ElementType.I1 :
509                                 writer.Write ((sbyte) elem.Value);
510                                 break;
511                         case ElementType.I2 :
512                                 writer.Write ((short) elem.Value);
513                                 break;
514                         case ElementType.I4 :
515                                 writer.Write ((int) elem.Value);
516                                 break;
517                         case ElementType.I8 :
518                                 writer.Write ((long) elem.Value);
519                                 break;
520                         case ElementType.U1 :
521                                 writer.Write ((byte) elem.Value);
522                                 break;
523                         case ElementType.U2 :
524                                 writer.Write ((ushort) elem.Value);
525                                 break;
526                         case ElementType.U4 :
527                                 writer.Write ((uint) elem.Value);
528                                 break;
529                         case ElementType.U8 :
530                                 writer.Write ((ulong) elem.Value);
531                                 break;
532                         case ElementType.String :
533                         case ElementType.Type :
534                                 string s = elem.Value as string;
535                                 if (s == null)
536                                         writer.Write ((byte) 0xff);
537                                 else if (s.Length == 0)
538                                         writer.Write ((byte) 0x00);
539                                 else
540                                         Write (s);
541                                 break;
542                         case ElementType.Object :
543                                 if (elem.Value != null)
544                                         throw new NotSupportedException ("Unknown state");
545                                 writer.Write ((byte) 0xff);
546                                 break;
547                         default :
548                                 throw new NotImplementedException ("WriteElem " + elem.FieldOrPropType.ToString ());
549                         }
550                 }
551
552                 void Write (string s)
553                 {
554                         byte [] str = Encoding.UTF8.GetBytes (s);
555                         Write (str.Length);
556                         m_sigWriter.Write (str);
557                 }
558
559                 void Write (int i)
560                 {
561                         Utilities.WriteCompressedInteger (m_sigWriter, i);
562                 }
563         }
564 }