Add attachable event support in XamlType (not yet in readers and writers).
[mono.git] / mcs / class / IKVM.Reflection / Signature.cs
1 /*
2   Copyright (C) 2009-2010 Jeroen Frijters
3
4   This software is provided 'as-is', without any express or implied
5   warranty.  In no event will the authors be held liable for any damages
6   arising from the use of this software.
7
8   Permission is granted to anyone to use this software for any purpose,
9   including commercial applications, and to alter it and redistribute it
10   freely, subject to the following restrictions:
11
12   1. The origin of this software must not be misrepresented; you must not
13      claim that you wrote the original software. If you use this software
14      in a product, an acknowledgment in the product documentation would be
15      appreciated but is not required.
16   2. Altered source versions must be plainly marked as such, and must not be
17      misrepresented as being the original software.
18   3. This notice may not be removed or altered from any source distribution.
19
20   Jeroen Frijters
21   jeroen@frijters.net
22   
23 */
24 using System;
25 using System.Collections.Generic;
26 using System.Diagnostics;
27 using System.IO;
28 using System.Text;
29 using CallingConvention = System.Runtime.InteropServices.CallingConvention;
30 using IKVM.Reflection.Reader;
31 using IKVM.Reflection.Emit;
32 using IKVM.Reflection.Writer;
33 using IKVM.Reflection.Metadata;
34
35 namespace IKVM.Reflection
36 {
37         abstract class Signature
38         {
39                 internal const byte DEFAULT = 0x00;
40                 internal const byte VARARG = 0x05;
41                 internal const byte GENERIC = 0x10;
42                 internal const byte HASTHIS = 0x20;
43                 internal const byte EXPLICITTHIS = 0x40;
44                 internal const byte FIELD = 0x06;
45                 internal const byte LOCAL_SIG = 0x07;
46                 internal const byte PROPERTY = 0x08;
47                 internal const byte GENERICINST = 0x0A;
48                 internal const byte SENTINEL = 0x41;
49                 internal const byte ELEMENT_TYPE_VOID = 0x01;
50                 internal const byte ELEMENT_TYPE_BOOLEAN = 0x02;
51                 internal const byte ELEMENT_TYPE_CHAR = 0x03;
52                 internal const byte ELEMENT_TYPE_I1 = 0x04;
53                 internal const byte ELEMENT_TYPE_U1 = 0x05;
54                 internal const byte ELEMENT_TYPE_I2 = 0x06;
55                 internal const byte ELEMENT_TYPE_U2 = 0x07;
56                 internal const byte ELEMENT_TYPE_I4 = 0x08;
57                 internal const byte ELEMENT_TYPE_U4 = 0x09;
58                 internal const byte ELEMENT_TYPE_I8 = 0x0a;
59                 internal const byte ELEMENT_TYPE_U8 = 0x0b;
60                 internal const byte ELEMENT_TYPE_R4 = 0x0c;
61                 internal const byte ELEMENT_TYPE_R8 = 0x0d;
62                 internal const byte ELEMENT_TYPE_STRING = 0x0e;
63                 internal const byte ELEMENT_TYPE_PTR = 0x0f;
64                 internal const byte ELEMENT_TYPE_BYREF = 0x10;
65                 internal const byte ELEMENT_TYPE_VALUETYPE = 0x11;
66                 internal const byte ELEMENT_TYPE_CLASS = 0x12;
67                 internal const byte ELEMENT_TYPE_VAR = 0x13;
68                 internal const byte ELEMENT_TYPE_ARRAY = 0x14;
69                 internal const byte ELEMENT_TYPE_GENERICINST = 0x15;
70                 internal const byte ELEMENT_TYPE_TYPEDBYREF = 0x16;
71                 internal const byte ELEMENT_TYPE_I = 0x18;
72                 internal const byte ELEMENT_TYPE_U = 0x19;
73                 internal const byte ELEMENT_TYPE_FNPTR = 0x1b;
74                 internal const byte ELEMENT_TYPE_OBJECT = 0x1c;
75                 internal const byte ELEMENT_TYPE_SZARRAY = 0x1d;
76                 internal const byte ELEMENT_TYPE_MVAR = 0x1e;
77                 internal const byte ELEMENT_TYPE_CMOD_REQD = 0x1f;
78                 internal const byte ELEMENT_TYPE_CMOD_OPT = 0x20;
79                 internal const byte ELEMENT_TYPE_PINNED = 0x45;
80
81                 internal abstract void WriteSig(ModuleBuilder module, ByteBuffer bb);
82
83                 private static Type ReadGenericInst(ModuleReader module, ByteReader br, IGenericContext context)
84                 {
85                         switch (br.ReadByte())
86                         {
87                                 case ELEMENT_TYPE_CLASS:
88                                 case ELEMENT_TYPE_VALUETYPE:
89                                         break;
90                                 default:
91                                         throw new BadImageFormatException();
92                         }
93                         Type type = ReadTypeDefOrRefEncoded(module, br, context);
94                         if (!type.IsGenericTypeDefinition)
95                         {
96                                 throw new BadImageFormatException();
97                         }
98                         int genArgCount = br.ReadCompressedInt();
99                         Type[] args = new Type[genArgCount];
100                         Type[][] reqmod = null;
101                         Type[][] optmod = null;
102                         for (int i = 0; i < genArgCount; i++)
103                         {
104                                 // LAMESPEC the Type production (23.2.12) doesn't include CustomMod* for genericinst, but C++ uses it, the verifier allows it and ildasm also supports it
105                                 CustomModifiers mods = ReadCustomModifiers(module, br, context);
106                                 if (mods.required != null || mods.optional != null)
107                                 {
108                                         if (reqmod == null)
109                                         {
110                                                 reqmod = new Type[genArgCount][];
111                                                 optmod = new Type[genArgCount][];
112                                         }
113                                         reqmod[i] = mods.required;
114                                         optmod[i] = mods.optional;
115                                 }
116                                 args[i] = ReadType(module, br, context);
117                         }
118                         return GenericTypeInstance.Make(type, args, reqmod, optmod);
119                 }
120
121                 internal static Type ReadTypeSpec(ModuleReader module, ByteReader br, IGenericContext context)
122                 {
123                         // LAMESPEC a TypeSpec can contain custom modifiers (C++/CLI generates "newarr (TypeSpec with custom modifiers)")
124                         SkipCustomModifiers(br);
125                         // LAMESPEC anything can be adorned by (useless) custom modifiers
126                         // also, VAR and MVAR are also used in TypeSpec (contrary to what the spec says)
127                         return ReadType(module, br, context);
128                 }
129
130                 private static Type ReadFunctionPointer(ModuleReader module, ByteReader br, IGenericContext context)
131                 {
132                         // TODO like .NET we return System.IntPtr here, but ideally we should fire an event in Universe that
133                         // the user can hook to provide a custom type (or we simply should build in full support for function pointer types)
134                         MethodSignature.ReadStandAloneMethodSig(module, br, context);
135                         return module.universe.System_IntPtr;
136                 }
137
138                 internal static Type[] ReadMethodSpec(ModuleReader module, ByteReader br, IGenericContext context)
139                 {
140                         if (br.ReadByte() != GENERICINST)
141                         {
142                                 throw new BadImageFormatException();
143                         }
144                         Type[] args = new Type[br.ReadCompressedInt()];
145                         for (int i = 0; i < args.Length; i++)
146                         {
147                                 args[i] = ReadType(module, br, context);
148                         }
149                         return args;
150                 }
151
152                 private static int ReadArrayShape(ByteReader br)
153                 {
154                         int rank = br.ReadCompressedInt();
155                         int numSizes = br.ReadCompressedInt();
156                         for (int i = 0; i < numSizes; i++)
157                         {
158                                 br.ReadCompressedInt();
159                         }
160                         int numLoBounds = br.ReadCompressedInt();
161                         for (int i = 0; i < numLoBounds; i++)
162                         {
163                                 br.ReadCompressedInt();
164                         }
165                         return rank;
166                 }
167
168                 private static Type ReadTypeOrVoid(ModuleReader module, ByteReader br, IGenericContext context)
169                 {
170                         if (br.PeekByte() == ELEMENT_TYPE_VOID)
171                         {
172                                 br.ReadByte();
173                                 return module.universe.System_Void;
174                         }
175                         else
176                         {
177                                 return ReadType(module, br, context);
178                         }
179                 }
180
181                 // see ECMA 335 CLI spec June 2006 section 23.2.12 for this production
182                 protected static Type ReadType(ModuleReader module, ByteReader br, IGenericContext context)
183                 {
184                         CustomModifiers mods;
185                         switch (br.ReadByte())
186                         {
187                                 case ELEMENT_TYPE_CLASS:
188                                 case ELEMENT_TYPE_VALUETYPE:
189                                         return ReadTypeDefOrRefEncoded(module, br, context);
190                                 case ELEMENT_TYPE_BOOLEAN:
191                                         return module.universe.System_Boolean;
192                                 case ELEMENT_TYPE_CHAR:
193                                         return module.universe.System_Char;
194                                 case ELEMENT_TYPE_I1:
195                                         return module.universe.System_SByte;
196                                 case ELEMENT_TYPE_U1:
197                                         return module.universe.System_Byte;
198                                 case ELEMENT_TYPE_I2:
199                                         return module.universe.System_Int16;
200                                 case ELEMENT_TYPE_U2:
201                                         return module.universe.System_UInt16;
202                                 case ELEMENT_TYPE_I4:
203                                         return module.universe.System_Int32;
204                                 case ELEMENT_TYPE_U4:
205                                         return module.universe.System_UInt32;
206                                 case ELEMENT_TYPE_I8:
207                                         return module.universe.System_Int64;
208                                 case ELEMENT_TYPE_U8:
209                                         return module.universe.System_UInt64;
210                                 case ELEMENT_TYPE_R4:
211                                         return module.universe.System_Single;
212                                 case ELEMENT_TYPE_R8:
213                                         return module.universe.System_Double;
214                                 case ELEMENT_TYPE_I:
215                                         return module.universe.System_IntPtr;
216                                 case ELEMENT_TYPE_U:
217                                         return module.universe.System_UIntPtr;
218                                 case ELEMENT_TYPE_STRING:
219                                         return module.universe.System_String;
220                                 case ELEMENT_TYPE_OBJECT:
221                                         return module.universe.System_Object;
222                                 case ELEMENT_TYPE_VAR:
223                                         return context.GetGenericTypeArgument(br.ReadCompressedInt());
224                                 case ELEMENT_TYPE_MVAR:
225                                         return context.GetGenericMethodArgument(br.ReadCompressedInt());
226                                 case ELEMENT_TYPE_GENERICINST:
227                                         return ReadGenericInst(module, br, context);
228                                 case ELEMENT_TYPE_SZARRAY:
229                                         mods = ReadCustomModifiers(module, br, context);
230                                         return ReadType(module, br, context).__MakeArrayType(mods.required, mods.optional);
231                                 case ELEMENT_TYPE_ARRAY:
232                                         mods = ReadCustomModifiers(module, br, context);
233                                         return ReadType(module, br, context).__MakeArrayType(ReadArrayShape(br), mods.required, mods.optional);
234                                 case ELEMENT_TYPE_PTR:
235                                         mods = ReadCustomModifiers(module, br, context);
236                                         return ReadTypeOrVoid(module, br, context).__MakePointerType(mods.required, mods.optional);
237                                 case ELEMENT_TYPE_FNPTR:
238                                         return ReadFunctionPointer(module, br, context);
239                                 default:
240                                         throw new BadImageFormatException();
241                         }
242                 }
243
244                 internal static void ReadLocalVarSig(ModuleReader module, ByteReader br, IGenericContext context, List<LocalVariableInfo> list)
245                 {
246                         if (br.Length < 2 || br.ReadByte() != LOCAL_SIG)
247                         {
248                                 throw new BadImageFormatException("Invalid local variable signature");
249                         }
250                         int count = br.ReadCompressedInt();
251                         for (int i = 0; i < count; i++)
252                         {
253                                 if (br.PeekByte() == ELEMENT_TYPE_TYPEDBYREF)
254                                 {
255                                         br.ReadByte();
256                                         list.Add(new LocalVariableInfo(i, module.universe.System_TypedReference, false));
257                                 }
258                                 else
259                                 {
260                                         SkipCustomModifiers(br);
261                                         bool pinned = false;
262                                         if (br.PeekByte() == ELEMENT_TYPE_PINNED)
263                                         {
264                                                 br.ReadByte();
265                                                 pinned = true;
266                                         }
267                                         SkipCustomModifiers(br);
268                                         Type type = ReadTypeOrByRef(module, br, context);
269                                         list.Add(new LocalVariableInfo(i, type, pinned));
270                                 }
271                         }
272                 }
273
274                 private static Type ReadTypeOrByRef(ModuleReader module, ByteReader br, IGenericContext context)
275                 {
276                         if (br.PeekByte() == ELEMENT_TYPE_BYREF)
277                         {
278                                 br.ReadByte();
279                                 // LAMESPEC it is allowed (by C++/CLI, ilasm and peverify) to have custom modifiers after the BYREF
280                                 // (which makes sense, as it is analogous to pointers)
281                                 CustomModifiers mods = ReadCustomModifiers(module, br, context);
282                                 // C++/CLI generates void& local variables, so we need to use ReadTypeOrVoid here
283                                 return ReadTypeOrVoid(module, br, context).__MakeByRefType(mods.required, mods.optional);
284                         }
285                         else
286                         {
287                                 return ReadType(module, br, context);
288                         }
289                 }
290
291                 protected static Type ReadRetType(ModuleReader module, ByteReader br, IGenericContext context)
292                 {
293                         switch (br.PeekByte())
294                         {
295                                 case ELEMENT_TYPE_VOID:
296                                         br.ReadByte();
297                                         return module.universe.System_Void;
298                                 case ELEMENT_TYPE_TYPEDBYREF:
299                                         br.ReadByte();
300                                         return module.universe.System_TypedReference;
301                                 default:
302                                         return ReadTypeOrByRef(module, br, context);
303                         }
304                 }
305
306                 protected static Type ReadParam(ModuleReader module, ByteReader br, IGenericContext context)
307                 {
308                         switch (br.PeekByte())
309                         {
310                                 case ELEMENT_TYPE_TYPEDBYREF:
311                                         br.ReadByte();
312                                         return module.universe.System_TypedReference;
313                                 default:
314                                         return ReadTypeOrByRef(module, br, context);
315                         }
316                 }
317
318                 protected static void WriteType(ModuleBuilder module, ByteBuffer bb, Type type)
319                 {
320                         while (type.HasElementType)
321                         {
322                                 if (type.__IsVector)
323                                 {
324                                         bb.Write(ELEMENT_TYPE_SZARRAY);
325                                 }
326                                 else if (type.IsArray)
327                                 {
328                                         int rank = type.GetArrayRank();
329                                         bb.Write(ELEMENT_TYPE_ARRAY);
330                                         // LAMESPEC the Type production (23.2.12) doesn't include CustomMod* for arrays, but the verifier allows it and ildasm also supports it
331                                         WriteCustomModifiers(module, bb, ELEMENT_TYPE_CMOD_REQD, type.__GetRequiredCustomModifiers());
332                                         WriteCustomModifiers(module, bb, ELEMENT_TYPE_CMOD_OPT, type.__GetOptionalCustomModifiers());
333                                         WriteType(module, bb, type.GetElementType());
334                                         bb.WriteCompressedInt(rank);
335                                         // since a Type doesn't contain the lower/upper bounds
336                                         // (they act like a custom modifier, so they are part of the signature, but not of the Type),
337                                         // we set them to the C# compatible values and hope for the best
338                                         bb.WriteCompressedInt(0);       // boundsCount
339                                         bb.WriteCompressedInt(rank);    // loCount
340                                         for (int i = 0; i < rank; i++)
341                                         {
342                                                 bb.WriteCompressedInt(0);
343                                         }
344                                         return;
345                                 }
346                                 else if (type.IsByRef)
347                                 {
348                                         bb.Write(ELEMENT_TYPE_BYREF);
349                                 }
350                                 else if (type.IsPointer)
351                                 {
352                                         bb.Write(ELEMENT_TYPE_PTR);
353                                 }
354                                 WriteCustomModifiers(module, bb, ELEMENT_TYPE_CMOD_REQD, type.__GetRequiredCustomModifiers());
355                                 WriteCustomModifiers(module, bb, ELEMENT_TYPE_CMOD_OPT, type.__GetOptionalCustomModifiers());
356                                 type = type.GetElementType();
357                         }
358                         Universe u = module.universe;
359                         if (type == u.System_Void)
360                         {
361                                 bb.Write(ELEMENT_TYPE_VOID);
362                         }
363                         else if (type == u.System_Boolean)
364                         {
365                                 bb.Write(ELEMENT_TYPE_BOOLEAN);
366                         }
367                         else if (type == u.System_Char)
368                         {
369                                 bb.Write(ELEMENT_TYPE_CHAR);
370                         }
371                         else if (type == u.System_SByte)
372                         {
373                                 bb.Write(ELEMENT_TYPE_I1);
374                         }
375                         else if (type == u.System_Byte)
376                         {
377                                 bb.Write(ELEMENT_TYPE_U1);
378                         }
379                         else if (type == u.System_Int16)
380                         {
381                                 bb.Write(ELEMENT_TYPE_I2);
382                         }
383                         else if (type == u.System_UInt16)
384                         {
385                                 bb.Write(ELEMENT_TYPE_U2);
386                         }
387                         else if (type == u.System_Int32)
388                         {
389                                 bb.Write(ELEMENT_TYPE_I4);
390                         }
391                         else if (type == u.System_UInt32)
392                         {
393                                 bb.Write(ELEMENT_TYPE_U4);
394                         }
395                         else if (type == u.System_Int64)
396                         {
397                                 bb.Write(ELEMENT_TYPE_I8);
398                         }
399                         else if (type == u.System_UInt64)
400                         {
401                                 bb.Write(ELEMENT_TYPE_U8);
402                         }
403                         else if (type == u.System_Single)
404                         {
405                                 bb.Write(ELEMENT_TYPE_R4);
406                         }
407                         else if (type == u.System_Double)
408                         {
409                                 bb.Write(ELEMENT_TYPE_R8);
410                         }
411                         else if (type == u.System_String)
412                         {
413                                 bb.Write(ELEMENT_TYPE_STRING);
414                         }
415                         else if (type == u.System_IntPtr)
416                         {
417                                 bb.Write(ELEMENT_TYPE_I);
418                         }
419                         else if (type == u.System_UIntPtr)
420                         {
421                                 bb.Write(ELEMENT_TYPE_U);
422                         }
423                         else if (type == u.System_TypedReference)
424                         {
425                                 bb.Write(ELEMENT_TYPE_TYPEDBYREF);
426                         }
427                         else if (type == u.System_Object)
428                         {
429                                 bb.Write(ELEMENT_TYPE_OBJECT);
430                         }
431                         else if (type.IsGenericParameter)
432                         {
433                                 if (type is UnboundGenericMethodParameter || type.DeclaringMethod != null)
434                                 {
435                                         bb.Write(ELEMENT_TYPE_MVAR);
436                                 }
437                                 else
438                                 {
439                                         bb.Write(ELEMENT_TYPE_VAR);
440                                 }
441                                 bb.WriteCompressedInt(type.GenericParameterPosition);
442                         }
443                         else if (type.IsGenericType)
444                         {
445                                 WriteGenericSignature(module, bb, type);
446                         }
447                         else
448                         {
449                                 if (type.IsValueType)
450                                 {
451                                         bb.Write(ELEMENT_TYPE_VALUETYPE);
452                                 }
453                                 else
454                                 {
455                                         bb.Write(ELEMENT_TYPE_CLASS);
456                                 }
457                                 bb.WriteTypeDefOrRefEncoded(module.GetTypeToken(type).Token);
458                         }
459                 }
460
461                 private static void WriteGenericSignature(ModuleBuilder module, ByteBuffer bb, Type type)
462                 {
463                         Type[] typeArguments = type.GetGenericArguments();
464                         Type[][] requiredCustomModifiers = type.__GetGenericArgumentsRequiredCustomModifiers();
465                         Type[][] optionalCustomModifiers = type.__GetGenericArgumentsOptionalCustomModifiers();
466                         if (!type.IsGenericTypeDefinition)
467                         {
468                                 type = type.GetGenericTypeDefinition();
469                         }
470                         bb.Write(ELEMENT_TYPE_GENERICINST);
471                         if (type.IsValueType)
472                         {
473                                 bb.Write(ELEMENT_TYPE_VALUETYPE);
474                         }
475                         else
476                         {
477                                 bb.Write(ELEMENT_TYPE_CLASS);
478                         }
479                         bb.WriteTypeDefOrRefEncoded(module.GetTypeToken(type).Token);
480                         bb.WriteCompressedInt(typeArguments.Length);
481                         for (int i = 0; i < typeArguments.Length; i++)
482                         {
483                                 WriteCustomModifiers(module, bb, ELEMENT_TYPE_CMOD_REQD, requiredCustomModifiers[i]);
484                                 WriteCustomModifiers(module, bb, ELEMENT_TYPE_CMOD_OPT, optionalCustomModifiers[i]);
485                                 WriteType(module, bb, typeArguments[i]);
486                         }
487                 }
488
489                 protected static void WriteCustomModifiers(ModuleBuilder module, ByteBuffer bb, byte mod, Type[] modifiers)
490                 {
491                         if (modifiers != null)
492                         {
493                                 foreach (Type type in modifiers)
494                                 {
495                                         bb.Write(mod);
496                                         bb.WriteTypeDefOrRefEncoded(module.GetTypeTokenForMemberRef(type));
497                                 }
498                         }
499                 }
500
501                 protected static bool IsCustomModifier(byte b)
502                 {
503                         return b == ELEMENT_TYPE_CMOD_OPT || b == ELEMENT_TYPE_CMOD_REQD;
504                 }
505
506                 struct CustomModifiers
507                 {
508                         internal Type[] required;
509                         internal Type[] optional;
510                 }
511
512                 private static CustomModifiers ReadCustomModifiers(ModuleReader module, ByteReader br, IGenericContext context)
513                 {
514                         CustomModifiers mods = new CustomModifiers();
515                         byte b = br.PeekByte();
516                         if (IsCustomModifier(b))
517                         {
518                                 List<Type> required = new List<Type>();
519                                 List<Type> optional = new List<Type>();
520                                 while (IsCustomModifier(b))
521                                 {
522                                         bool req = br.ReadByte() == ELEMENT_TYPE_CMOD_REQD;
523                                         Type type = ReadTypeDefOrRefEncoded(module, br, context);
524                                         (req ? required : optional).Add(type);
525                                         b = br.PeekByte();
526                                 }
527                                 mods.required = required.ToArray();
528                                 mods.optional = optional.ToArray();
529                         }
530                         return mods;
531                 }
532
533                 protected static void SkipCustomModifiers(ByteReader br)
534                 {
535                         byte b = br.PeekByte();
536                         while (IsCustomModifier(b))
537                         {
538                                 br.ReadByte();
539                                 br.ReadCompressedInt();
540                                 b = br.PeekByte();
541                         }
542                 }
543
544                 private static Type ReadTypeDefOrRefEncoded(ModuleReader module, ByteReader br, IGenericContext context)
545                 {
546                         int encoded = br.ReadCompressedInt();
547                         switch (encoded & 3)
548                         {
549                                 case 0:
550                                         return module.ResolveType((TypeDefTable.Index << 24) + (encoded >> 2), null, null);
551                                 case 1:
552                                         return module.ResolveType((TypeRefTable.Index << 24) + (encoded >> 2), null, null);
553                                 case 2:
554                                         return module.ResolveType((TypeSpecTable.Index << 24) + (encoded >> 2), context);
555                                 default:
556                                         throw new BadImageFormatException();
557                         }
558                 }
559
560                 protected static void ReadCustomModifiers(ModuleReader module, ByteReader br, IGenericContext context, out Type[] requiredCustomModifiers, out Type[] optionalCustomModifiers)
561                 {
562                         byte b = br.PeekByte();
563                         if (IsCustomModifier(b))
564                         {
565                                 List<Type> required = new List<Type>();
566                                 List<Type> optional = new List<Type>();
567                                 while (IsCustomModifier(b))
568                                 {
569                                         br.ReadByte();
570                                         Type type = ReadTypeDefOrRefEncoded(module, br, context);
571                                         if (b == ELEMENT_TYPE_CMOD_REQD)
572                                         {
573                                                 required.Add(type);
574                                         }
575                                         else
576                                         {
577                                                 optional.Add(type);
578                                         }
579                                         b = br.PeekByte();
580                                 }
581                                 requiredCustomModifiers = required.ToArray();
582                                 optionalCustomModifiers = optional.ToArray();
583                         }
584                         else
585                         {
586                                 requiredCustomModifiers = null;
587                                 optionalCustomModifiers = null;
588                         }
589                 }
590
591                 // unmanaged calling convention
592                 internal static void WriteStandAloneMethodSig(ModuleBuilder module, ByteBuffer bb, CallingConvention callingConvention, Type returnType, Type[] parameterTypes)
593                 {
594                         switch (callingConvention)
595                         {
596                                 case CallingConvention.Cdecl:
597                                         bb.Write((byte)0x01);   // C
598                                         break;
599                                 case CallingConvention.StdCall:
600                                 case CallingConvention.Winapi:
601                                         bb.Write((byte)0x02);   // STDCALL
602                                         break;
603                                 case CallingConvention.ThisCall:
604                                         bb.Write((byte)0x03);   // THISCALL
605                                         break;
606                                 case CallingConvention.FastCall:
607                                         bb.Write((byte)0x04);   // FASTCALL
608                                         break;
609                                 default:
610                                         throw new ArgumentOutOfRangeException("callingConvention");
611                         }
612                         bb.WriteCompressedInt(parameterTypes.Length);
613                         WriteType(module, bb, returnType);
614                         foreach (Type t in parameterTypes)
615                         {
616                                 WriteType(module, bb, t);
617                         }
618                 }
619
620                 // managed calling convention
621                 internal static void WriteStandAloneMethodSig(ModuleBuilder module, ByteBuffer bb, CallingConventions callingConvention, Type returnType, Type[] parameterTypes, Type[] optionalParameterTypes)
622                 {
623                         byte flags = 0;
624                         if ((callingConvention & CallingConventions.HasThis) != 0)
625                         {
626                                 flags |= HASTHIS;
627                         }
628                         if ((callingConvention & CallingConventions.ExplicitThis) != 0)
629                         {
630                                 flags |= EXPLICITTHIS;
631                         }
632                         if ((callingConvention & CallingConventions.VarArgs) != 0)
633                         {
634                                 flags |= VARARG;
635                         }
636                         bb.Write(flags);
637                         bb.WriteCompressedInt(parameterTypes.Length + optionalParameterTypes.Length);
638                         WriteType(module, bb, returnType);
639                         foreach (Type t in parameterTypes)
640                         {
641                                 WriteType(module, bb, t);
642                         }
643                         if (optionalParameterTypes.Length > 0)
644                         {
645                                 bb.Write(SENTINEL);
646                                 foreach (Type t in optionalParameterTypes)
647                                 {
648                                         WriteType(module, bb, t);
649                                 }
650                         }
651                 }
652
653                 internal static void WriteLocalVarSig(ModuleBuilder module, ByteBuffer bb, IList<LocalBuilder> locals)
654                 {
655                         bb.Write(LOCAL_SIG);
656                         bb.WriteCompressedInt(locals.Count);
657                         foreach (LocalBuilder local in locals)
658                         {
659                                 if (local.IsPinned)
660                                 {
661                                         bb.Write(ELEMENT_TYPE_PINNED);
662                                 }
663                                 WriteType(module, bb, local.LocalType);
664                         }
665                 }
666
667                 internal static void WritePropertySig(ModuleBuilder module, ByteBuffer bb, CallingConventions callingConvention,
668                         Type returnType, Type[] returnTypeRequiredCustomModifiers, Type[] returnTypeOptionalCustomModifiers,
669                         Type[] parameterTypes, Type[][] parameterTypeRequiredCustomModifiers, Type[][] parameterTypeOptionalCustomModifiers)
670                 {
671                         byte flags = PROPERTY;
672                         if ((callingConvention & CallingConventions.HasThis) != 0)
673                         {
674                                 flags |= HASTHIS;
675                         }
676                         if ((callingConvention & CallingConventions.ExplicitThis) != 0)
677                         {
678                                 flags |= EXPLICITTHIS;
679                         }
680                         if ((callingConvention & CallingConventions.VarArgs) != 0)
681                         {
682                                 flags |= VARARG;
683                         }
684                         bb.Write(flags);
685                         bb.WriteCompressedInt(parameterTypes == null ? 0 : parameterTypes.Length);
686                         WriteCustomModifiers(module, bb, ELEMENT_TYPE_CMOD_REQD, returnTypeRequiredCustomModifiers);
687                         WriteCustomModifiers(module, bb, ELEMENT_TYPE_CMOD_OPT, returnTypeOptionalCustomModifiers);
688                         WriteType(module, bb, returnType);
689                         if (parameterTypes != null)
690                         {
691                                 for (int i = 0; i < parameterTypes.Length; i++)
692                                 {
693                                         if (parameterTypeRequiredCustomModifiers != null)
694                                         {
695                                                 WriteCustomModifiers(module, bb, ELEMENT_TYPE_CMOD_REQD, parameterTypeRequiredCustomModifiers[i]);
696                                         }
697                                         if (parameterTypeOptionalCustomModifiers != null)
698                                         {
699                                                 WriteCustomModifiers(module, bb, ELEMENT_TYPE_CMOD_OPT, parameterTypeOptionalCustomModifiers[i]);
700                                         }
701                                         WriteType(module, bb, parameterTypes[i]);
702                                 }
703                         }
704                 }
705
706                 internal static void WriteTypeSpec(ModuleBuilder module, ByteBuffer bb, Type type)
707                 {
708                         WriteType(module, bb, type);
709                 }
710
711                 internal static void WriteMethodSpec(ModuleBuilder module, ByteBuffer bb, Type[] genArgs)
712                 {
713                         bb.Write(GENERICINST);
714                         bb.WriteCompressedInt(genArgs.Length);
715                         foreach (Type arg in genArgs)
716                         {
717                                 WriteType(module, bb, arg);
718                         }
719                 }
720
721                 // this reads just the optional parameter types, from a MethodRefSig
722                 internal static Type[] ReadOptionalParameterTypes(ModuleReader module, ByteReader br)
723                 {
724                         br.ReadByte();
725                         int paramCount = br.ReadCompressedInt();
726                         SkipCustomModifiers(br);
727                         ReadRetType(module, br, null);
728                         for (int i = 0; i < paramCount; i++)
729                         {
730                                 if (br.PeekByte() == SENTINEL)
731                                 {
732                                         br.ReadByte();
733                                         Type[] types = new Type[paramCount - i];
734                                         for (int j = 0; j < types.Length; j++)
735                                         {
736                                                 SkipCustomModifiers(br);
737                                                 types[j] = ReadType(module, br, null);
738                                         }
739                                         return types;
740                                 }
741                                 SkipCustomModifiers(br);
742                                 ReadType(module, br, null);
743                         }
744                         return Type.EmptyTypes;
745                 }
746
747                 protected static Type[] BindTypeParameters(IGenericBinder binder, Type[] types)
748                 {
749                         if (types == null || types.Length == 0)
750                         {
751                                 return Type.EmptyTypes;
752                         }
753                         Type[] expanded = new Type[types.Length];
754                         for (int i = 0; i < types.Length; i++)
755                         {
756                                 expanded[i] = types[i].BindTypeParameters(binder);
757                         }
758                         return expanded;
759                 }
760
761                 protected static Type[][] BindTypeParameters(IGenericBinder binder, Type[][] types)
762                 {
763                         if (types == null)
764                         {
765                                 return null;
766                         }
767                         Type[][] expanded = new Type[types.Length][];
768                         for (int i = 0; i < types.Length; i++)
769                         {
770                                 expanded[i] = BindTypeParameters(binder, types[i]);
771                         }
772                         return expanded;
773                 }
774
775                 protected static Type[][][] BindTypeParameters(IGenericBinder binder, Type[][][] types)
776                 {
777                         if (types == null)
778                         {
779                                 return null;
780                         }
781                         Type[][][] expanded = new Type[types.Length][][];
782                         for (int i = 0; i < types.Length; i++)
783                         {
784                                 expanded[i] = BindTypeParameters(binder, types[i]);
785                         }
786                         return expanded;
787                 }
788
789                 protected static Type[] BindTypeParameters(IGenericBinder binder, Type[][][] types, int index, int optOrReq)
790                 {
791                         if (types == null || types[index] == null)
792                         {
793                                 return null;
794                         }
795                         return BindTypeParameters(binder, types[index][optOrReq]);
796                 }
797         }
798 }