Merge pull request #347 from JamesB7/master
[mono.git] / mcs / class / IKVM.Reflection / Signature.cs
1 /*
2   Copyright (C) 2009-2012 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                         Type type;
86                         switch (br.ReadByte())
87                         {
88                                 case ELEMENT_TYPE_CLASS:
89                                         type = ReadTypeDefOrRefEncoded(module, br, context).MarkNotValueType();
90                                         break;
91                                 case ELEMENT_TYPE_VALUETYPE:
92                                         type = ReadTypeDefOrRefEncoded(module, br, context).MarkValueType();
93                                         break;
94                                 default:
95                                         throw new BadImageFormatException();
96                         }
97                         if (!type.__IsMissing && !type.IsGenericTypeDefinition)
98                         {
99                                 throw new BadImageFormatException();
100                         }
101                         int genArgCount = br.ReadCompressedInt();
102                         Type[] args = new Type[genArgCount];
103                         CustomModifiers[] mods = null;
104                         for (int i = 0; i < genArgCount; i++)
105                         {
106                                 // 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
107                                 CustomModifiers cm = CustomModifiers.Read(module, br, context);
108                                 if (!cm.IsEmpty)
109                                 {
110                                         if (mods == null)
111                                         {
112                                                 mods = new CustomModifiers[genArgCount];
113                                         }
114                                         mods[i] = cm;
115                                 }
116                                 args[i] = ReadType(module, br, context);
117                         }
118                         return GenericTypeInstance.Make(type, args, mods);
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                         CustomModifiers.Skip(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                         __StandAloneMethodSig sig = MethodSignature.ReadStandAloneMethodSig(module, br, context);
133                         if (module.universe.EnableFunctionPointers)
134                         {
135                                 return FunctionPointerType.Make(module.universe, sig);
136                         }
137                         else
138                         {
139                                 // by default, like .NET we return System.IntPtr here
140                                 return module.universe.System_IntPtr;
141                         }
142                 }
143
144                 internal static Type[] ReadMethodSpec(ModuleReader module, ByteReader br, IGenericContext context)
145                 {
146                         if (br.ReadByte() != GENERICINST)
147                         {
148                                 throw new BadImageFormatException();
149                         }
150                         Type[] args = new Type[br.ReadCompressedInt()];
151                         for (int i = 0; i < args.Length; i++)
152                         {
153                                 args[i] = ReadType(module, br, context);
154                         }
155                         return args;
156                 }
157
158                 private static int[] ReadArrayBounds(ByteReader br)
159                 {
160                         int num = br.ReadCompressedInt();
161                         if (num == 0)
162                         {
163                                 return null;
164                         }
165                         int[] arr = new int[num];
166                         for (int i = 0; i < num; i++)
167                         {
168                                 arr[i] = br.ReadCompressedInt();
169                         }
170                         return arr;
171                 }
172
173                 private static Type ReadTypeOrVoid(ModuleReader module, ByteReader br, IGenericContext context)
174                 {
175                         if (br.PeekByte() == ELEMENT_TYPE_VOID)
176                         {
177                                 br.ReadByte();
178                                 return module.universe.System_Void;
179                         }
180                         else
181                         {
182                                 return ReadType(module, br, context);
183                         }
184                 }
185
186                 // see ECMA 335 CLI spec June 2006 section 23.2.12 for this production
187                 protected static Type ReadType(ModuleReader module, ByteReader br, IGenericContext context)
188                 {
189                         CustomModifiers mods;
190                         switch (br.ReadByte())
191                         {
192                                 case ELEMENT_TYPE_CLASS:
193                                         return ReadTypeDefOrRefEncoded(module, br, context).MarkNotValueType();
194                                 case ELEMENT_TYPE_VALUETYPE:
195                                         return ReadTypeDefOrRefEncoded(module, br, context).MarkValueType();
196                                 case ELEMENT_TYPE_BOOLEAN:
197                                         return module.universe.System_Boolean;
198                                 case ELEMENT_TYPE_CHAR:
199                                         return module.universe.System_Char;
200                                 case ELEMENT_TYPE_I1:
201                                         return module.universe.System_SByte;
202                                 case ELEMENT_TYPE_U1:
203                                         return module.universe.System_Byte;
204                                 case ELEMENT_TYPE_I2:
205                                         return module.universe.System_Int16;
206                                 case ELEMENT_TYPE_U2:
207                                         return module.universe.System_UInt16;
208                                 case ELEMENT_TYPE_I4:
209                                         return module.universe.System_Int32;
210                                 case ELEMENT_TYPE_U4:
211                                         return module.universe.System_UInt32;
212                                 case ELEMENT_TYPE_I8:
213                                         return module.universe.System_Int64;
214                                 case ELEMENT_TYPE_U8:
215                                         return module.universe.System_UInt64;
216                                 case ELEMENT_TYPE_R4:
217                                         return module.universe.System_Single;
218                                 case ELEMENT_TYPE_R8:
219                                         return module.universe.System_Double;
220                                 case ELEMENT_TYPE_I:
221                                         return module.universe.System_IntPtr;
222                                 case ELEMENT_TYPE_U:
223                                         return module.universe.System_UIntPtr;
224                                 case ELEMENT_TYPE_STRING:
225                                         return module.universe.System_String;
226                                 case ELEMENT_TYPE_OBJECT:
227                                         return module.universe.System_Object;
228                                 case ELEMENT_TYPE_VAR:
229                                         return context.GetGenericTypeArgument(br.ReadCompressedInt());
230                                 case ELEMENT_TYPE_MVAR:
231                                         return context.GetGenericMethodArgument(br.ReadCompressedInt());
232                                 case ELEMENT_TYPE_GENERICINST:
233                                         return ReadGenericInst(module, br, context);
234                                 case ELEMENT_TYPE_SZARRAY:
235                                         mods = CustomModifiers.Read(module, br, context);
236                                         return ReadType(module, br, context).__MakeArrayType(mods);
237                                 case ELEMENT_TYPE_ARRAY:
238                                         mods = CustomModifiers.Read(module, br, context);
239                                         return ReadType(module, br, context).__MakeArrayType(br.ReadCompressedInt(), ReadArrayBounds(br), ReadArrayBounds(br), mods);
240                                 case ELEMENT_TYPE_PTR:
241                                         mods = CustomModifiers.Read(module, br, context);
242                                         return ReadTypeOrVoid(module, br, context).__MakePointerType(mods);
243                                 case ELEMENT_TYPE_FNPTR:
244                                         return ReadFunctionPointer(module, br, context);
245                                 default:
246                                         throw new BadImageFormatException();
247                         }
248                 }
249
250                 internal static void ReadLocalVarSig(ModuleReader module, ByteReader br, IGenericContext context, List<LocalVariableInfo> list)
251                 {
252                         if (br.Length < 2 || br.ReadByte() != LOCAL_SIG)
253                         {
254                                 throw new BadImageFormatException("Invalid local variable signature");
255                         }
256                         int count = br.ReadCompressedInt();
257                         for (int i = 0; i < count; i++)
258                         {
259                                 if (br.PeekByte() == ELEMENT_TYPE_TYPEDBYREF)
260                                 {
261                                         br.ReadByte();
262                                         list.Add(new LocalVariableInfo(i, module.universe.System_TypedReference, false, new CustomModifiers()));
263                                 }
264                                 else
265                                 {
266                                         CustomModifiers mods1 = CustomModifiers.Read(module, br, context);
267                                         bool pinned = false;
268                                         if (br.PeekByte() == ELEMENT_TYPE_PINNED)
269                                         {
270                                                 br.ReadByte();
271                                                 pinned = true;
272                                         }
273                                         CustomModifiers mods2 = CustomModifiers.Read(module, br, context);
274                                         Type type = ReadTypeOrByRef(module, br, context);
275                                         list.Add(new LocalVariableInfo(i, type, pinned, CustomModifiers.Combine(mods1, mods2)));
276                                 }
277                         }
278                 }
279
280                 private static Type ReadTypeOrByRef(ModuleReader module, ByteReader br, IGenericContext context)
281                 {
282                         if (br.PeekByte() == ELEMENT_TYPE_BYREF)
283                         {
284                                 br.ReadByte();
285                                 // LAMESPEC it is allowed (by C++/CLI, ilasm and peverify) to have custom modifiers after the BYREF
286                                 // (which makes sense, as it is analogous to pointers)
287                                 CustomModifiers mods = CustomModifiers.Read(module, br, context);
288                                 // C++/CLI generates void& local variables, so we need to use ReadTypeOrVoid here
289                                 return ReadTypeOrVoid(module, br, context).__MakeByRefType(mods);
290                         }
291                         else
292                         {
293                                 return ReadType(module, br, context);
294                         }
295                 }
296
297                 protected static Type ReadRetType(ModuleReader module, ByteReader br, IGenericContext context)
298                 {
299                         switch (br.PeekByte())
300                         {
301                                 case ELEMENT_TYPE_VOID:
302                                         br.ReadByte();
303                                         return module.universe.System_Void;
304                                 case ELEMENT_TYPE_TYPEDBYREF:
305                                         br.ReadByte();
306                                         return module.universe.System_TypedReference;
307                                 default:
308                                         return ReadTypeOrByRef(module, br, context);
309                         }
310                 }
311
312                 protected static Type ReadParam(ModuleReader module, ByteReader br, IGenericContext context)
313                 {
314                         switch (br.PeekByte())
315                         {
316                                 case ELEMENT_TYPE_TYPEDBYREF:
317                                         br.ReadByte();
318                                         return module.universe.System_TypedReference;
319                                 default:
320                                         return ReadTypeOrByRef(module, br, context);
321                         }
322                 }
323
324                 protected static void WriteType(ModuleBuilder module, ByteBuffer bb, Type type)
325                 {
326                         while (type.HasElementType)
327                         {
328                                 if (type.__IsVector)
329                                 {
330                                         bb.Write(ELEMENT_TYPE_SZARRAY);
331                                 }
332                                 else if (type.IsArray)
333                                 {
334                                         int rank = type.GetArrayRank();
335                                         bb.Write(ELEMENT_TYPE_ARRAY);
336                                         // LAMESPEC the Type production (23.2.12) doesn't include CustomMod* for arrays, but the verifier allows it and ildasm also supports it
337                                         WriteCustomModifiers(module, bb, type.__GetCustomModifiers());
338                                         WriteType(module, bb, type.GetElementType());
339                                         bb.WriteCompressedInt(rank);
340                                         int[] sizes = type.__GetArraySizes();
341                                         bb.WriteCompressedInt(sizes.Length);
342                                         for (int i = 0; i < sizes.Length; i++)
343                                         {
344                                                 bb.WriteCompressedInt(sizes[i]);
345                                         }
346                                         int[] lobounds = type.__GetArrayLowerBounds();
347                                         bb.WriteCompressedInt(lobounds.Length);
348                                         for (int i = 0; i < lobounds.Length; i++)
349                                         {
350                                                 bb.WriteCompressedInt(lobounds[i]);
351                                         }
352                                         return;
353                                 }
354                                 else if (type.IsByRef)
355                                 {
356                                         bb.Write(ELEMENT_TYPE_BYREF);
357                                 }
358                                 else if (type.IsPointer)
359                                 {
360                                         bb.Write(ELEMENT_TYPE_PTR);
361                                 }
362                                 WriteCustomModifiers(module, bb, type.__GetCustomModifiers());
363                                 type = type.GetElementType();
364                         }
365                         Universe u = module.universe;
366                         if (type == u.System_Void)
367                         {
368                                 bb.Write(ELEMENT_TYPE_VOID);
369                         }
370                         else if (type == u.System_Int32)
371                         {
372                                 bb.Write(ELEMENT_TYPE_I4);
373                         }
374                         else if (type == u.System_Boolean)
375                         {
376                                 bb.Write(ELEMENT_TYPE_BOOLEAN);
377                         }
378                         else if (type == u.System_String)
379                         {
380                                 bb.Write(ELEMENT_TYPE_STRING);
381                         }
382                         else if (type == u.System_Char)
383                         {
384                                 bb.Write(ELEMENT_TYPE_CHAR);
385                         }
386                         else if (type == u.System_SByte)
387                         {
388                                 bb.Write(ELEMENT_TYPE_I1);
389                         }
390                         else if (type == u.System_Byte)
391                         {
392                                 bb.Write(ELEMENT_TYPE_U1);
393                         }
394                         else if (type == u.System_Int16)
395                         {
396                                 bb.Write(ELEMENT_TYPE_I2);
397                         }
398                         else if (type == u.System_UInt16)
399                         {
400                                 bb.Write(ELEMENT_TYPE_U2);
401                         }
402                         else if (type == u.System_UInt32)
403                         {
404                                 bb.Write(ELEMENT_TYPE_U4);
405                         }
406                         else if (type == u.System_Int64)
407                         {
408                                 bb.Write(ELEMENT_TYPE_I8);
409                         }
410                         else if (type == u.System_UInt64)
411                         {
412                                 bb.Write(ELEMENT_TYPE_U8);
413                         }
414                         else if (type == u.System_Single)
415                         {
416                                 bb.Write(ELEMENT_TYPE_R4);
417                         }
418                         else if (type == u.System_Double)
419                         {
420                                 bb.Write(ELEMENT_TYPE_R8);
421                         }
422                         else if (type == u.System_IntPtr)
423                         {
424                                 bb.Write(ELEMENT_TYPE_I);
425                         }
426                         else if (type == u.System_UIntPtr)
427                         {
428                                 bb.Write(ELEMENT_TYPE_U);
429                         }
430                         else if (type == u.System_TypedReference)
431                         {
432                                 bb.Write(ELEMENT_TYPE_TYPEDBYREF);
433                         }
434                         else if (type == u.System_Object)
435                         {
436                                 bb.Write(ELEMENT_TYPE_OBJECT);
437                         }
438                         else if (type.IsGenericParameter)
439                         {
440                                 if (type is UnboundGenericMethodParameter || type.DeclaringMethod != null)
441                                 {
442                                         bb.Write(ELEMENT_TYPE_MVAR);
443                                 }
444                                 else
445                                 {
446                                         bb.Write(ELEMENT_TYPE_VAR);
447                                 }
448                                 bb.WriteCompressedInt(type.GenericParameterPosition);
449                         }
450                         else if (!type.__IsMissing && type.IsGenericType)
451                         {
452                                 WriteGenericSignature(module, bb, type);
453                         }
454                         else if (type.__IsFunctionPointer)
455                         {
456                                 bb.Write(ELEMENT_TYPE_FNPTR);
457                                 WriteStandAloneMethodSig(module, bb, type.__MethodSignature);
458                         }
459                         else
460                         {
461                                 if (type.IsValueType)
462                                 {
463                                         bb.Write(ELEMENT_TYPE_VALUETYPE);
464                                 }
465                                 else
466                                 {
467                                         bb.Write(ELEMENT_TYPE_CLASS);
468                                 }
469                                 bb.WriteTypeDefOrRefEncoded(module.GetTypeToken(type).Token);
470                         }
471                 }
472
473                 private static void WriteGenericSignature(ModuleBuilder module, ByteBuffer bb, Type type)
474                 {
475                         Type[] typeArguments = type.GetGenericArguments();
476                         CustomModifiers[] customModifiers = type.__GetGenericArgumentsCustomModifiers();
477                         if (!type.IsGenericTypeDefinition)
478                         {
479                                 type = type.GetGenericTypeDefinition();
480                         }
481                         bb.Write(ELEMENT_TYPE_GENERICINST);
482                         if (type.IsValueType)
483                         {
484                                 bb.Write(ELEMENT_TYPE_VALUETYPE);
485                         }
486                         else
487                         {
488                                 bb.Write(ELEMENT_TYPE_CLASS);
489                         }
490                         bb.WriteTypeDefOrRefEncoded(module.GetTypeToken(type).Token);
491                         bb.WriteCompressedInt(typeArguments.Length);
492                         for (int i = 0; i < typeArguments.Length; i++)
493                         {
494                                 WriteCustomModifiers(module, bb, customModifiers[i]);
495                                 WriteType(module, bb, typeArguments[i]);
496                         }
497                 }
498
499                 protected static void WriteCustomModifiers(ModuleBuilder module, ByteBuffer bb, CustomModifiers modifiers)
500                 {
501                         foreach (CustomModifiers.Entry entry in modifiers)
502                         {
503                                 bb.Write(entry.IsRequired ? ELEMENT_TYPE_CMOD_REQD : ELEMENT_TYPE_CMOD_OPT);
504                                 bb.WriteTypeDefOrRefEncoded(module.GetTypeTokenForMemberRef(entry.Type));
505                         }
506                 }
507
508                 internal static Type ReadTypeDefOrRefEncoded(ModuleReader module, ByteReader br, IGenericContext context)
509                 {
510                         int encoded = br.ReadCompressedInt();
511                         switch (encoded & 3)
512                         {
513                                 case 0:
514                                         return module.ResolveType((TypeDefTable.Index << 24) + (encoded >> 2), null, null);
515                                 case 1:
516                                         return module.ResolveType((TypeRefTable.Index << 24) + (encoded >> 2), null, null);
517                                 case 2:
518                                         return module.ResolveType((TypeSpecTable.Index << 24) + (encoded >> 2), context);
519                                 default:
520                                         throw new BadImageFormatException();
521                         }
522                 }
523
524                 internal static void WriteStandAloneMethodSig(ModuleBuilder module, ByteBuffer bb, __StandAloneMethodSig sig)
525                 {
526                         if (sig.IsUnmanaged)
527                         {
528                                 switch (sig.UnmanagedCallingConvention)
529                                 {
530                                         case CallingConvention.Cdecl:
531                                                 bb.Write((byte)0x01);   // C
532                                                 break;
533                                         case CallingConvention.StdCall:
534                                         case CallingConvention.Winapi:
535                                                 bb.Write((byte)0x02);   // STDCALL
536                                                 break;
537                                         case CallingConvention.ThisCall:
538                                                 bb.Write((byte)0x03);   // THISCALL
539                                                 break;
540                                         case CallingConvention.FastCall:
541                                                 bb.Write((byte)0x04);   // FASTCALL
542                                                 break;
543                                         default:
544                                                 throw new ArgumentOutOfRangeException("callingConvention");
545                                 }
546                         }
547                         else
548                         {
549                                 CallingConventions callingConvention = sig.CallingConvention;
550                                 byte flags = 0;
551                                 if ((callingConvention & CallingConventions.HasThis) != 0)
552                                 {
553                                         flags |= HASTHIS;
554                                 }
555                                 if ((callingConvention & CallingConventions.ExplicitThis) != 0)
556                                 {
557                                         flags |= EXPLICITTHIS;
558                                 }
559                                 if ((callingConvention & CallingConventions.VarArgs) != 0)
560                                 {
561                                         flags |= VARARG;
562                                 }
563                                 bb.Write(flags);
564                         }
565                         Type[] parameterTypes = sig.ParameterTypes;
566                         Type[] optionalParameterTypes = sig.OptionalParameterTypes;
567                         bb.WriteCompressedInt(parameterTypes.Length + optionalParameterTypes.Length);
568                         WriteCustomModifiers(module, bb, sig.GetReturnTypeCustomModifiers());
569                         WriteType(module, bb, sig.ReturnType);
570                         int index = 0;
571                         foreach (Type t in parameterTypes)
572                         {
573                                 WriteCustomModifiers(module, bb, sig.GetParameterCustomModifiers(index++));
574                                 WriteType(module, bb, t);
575                         }
576                         // note that optional parameters are only allowed for managed signatures (but we don't enforce that)
577                         if (optionalParameterTypes.Length > 0)
578                         {
579                                 bb.Write(SENTINEL);
580                                 foreach (Type t in optionalParameterTypes)
581                                 {
582                                         WriteCustomModifiers(module, bb, sig.GetParameterCustomModifiers(index++));
583                                         WriteType(module, bb, t);
584                                 }
585                         }
586                 }
587
588                 internal static void WriteTypeSpec(ModuleBuilder module, ByteBuffer bb, Type type)
589                 {
590                         WriteType(module, bb, type);
591                 }
592
593                 internal static void WriteMethodSpec(ModuleBuilder module, ByteBuffer bb, Type[] genArgs)
594                 {
595                         bb.Write(GENERICINST);
596                         bb.WriteCompressedInt(genArgs.Length);
597                         foreach (Type arg in genArgs)
598                         {
599                                 WriteType(module, bb, arg);
600                         }
601                 }
602
603                 // this reads just the optional parameter types, from a MethodRefSig
604                 internal static Type[] ReadOptionalParameterTypes(ModuleReader module, ByteReader br, IGenericContext context, out CustomModifiers[] customModifiers)
605                 {
606                         br.ReadByte();
607                         int paramCount = br.ReadCompressedInt();
608                         CustomModifiers.Skip(br);
609                         ReadRetType(module, br, context);
610                         for (int i = 0; i < paramCount; i++)
611                         {
612                                 if (br.PeekByte() == SENTINEL)
613                                 {
614                                         br.ReadByte();
615                                         Type[] types = new Type[paramCount - i];
616                                         customModifiers = new CustomModifiers[types.Length];
617                                         for (int j = 0; j < types.Length; j++)
618                                         {
619                                                 customModifiers[j] = CustomModifiers.Read(module, br, context);
620                                                 types[j] = ReadType(module, br, context);
621                                         }
622                                         return types;
623                                 }
624                                 CustomModifiers.Skip(br);
625                                 ReadType(module, br, context);
626                         }
627                         customModifiers = Empty<CustomModifiers>.Array;
628                         return Type.EmptyTypes;
629                 }
630
631                 protected static Type[] BindTypeParameters(IGenericBinder binder, Type[] types)
632                 {
633                         if (types == null || types.Length == 0)
634                         {
635                                 return Type.EmptyTypes;
636                         }
637                         Type[] expanded = new Type[types.Length];
638                         for (int i = 0; i < types.Length; i++)
639                         {
640                                 expanded[i] = types[i].BindTypeParameters(binder);
641                         }
642                         return expanded;
643                 }
644
645                 internal static void WriteSignatureHelper(ModuleBuilder module, ByteBuffer bb, byte flags, ushort paramCount, List<Type> args)
646                 {
647                         bb.Write(flags);
648                         if (flags != FIELD)
649                         {
650                                 bb.WriteCompressedInt(paramCount);
651                         }
652                         foreach (Type type in args)
653                         {
654                                 if (type == MarkerType.ModOpt)
655                                 {
656                                         bb.Write(ELEMENT_TYPE_CMOD_OPT);
657                                 }
658                                 else if (type == MarkerType.ModReq)
659                                 {
660                                         bb.Write(ELEMENT_TYPE_CMOD_REQD);
661                                 }
662                                 else if (type == MarkerType.Sentinel)
663                                 {
664                                         bb.Write(SENTINEL);
665                                 }
666                                 else if (type == MarkerType.Pinned)
667                                 {
668                                         bb.Write(ELEMENT_TYPE_PINNED);
669                                 }
670                                 else if (type == null)
671                                 {
672                                         bb.Write(ELEMENT_TYPE_VOID);
673                                 }
674                                 else
675                                 {
676                                         WriteType(module, bb, type);
677                                 }
678                         }
679                 }
680         }
681 }