do not check order sequence if option /order was not used
[mono.git] / mcs / class / IKVM.Reflection / MethodSignature.cs
1 /*
2   Copyright (C) 2009-2011 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 IKVM.Reflection.Reader;
28 using IKVM.Reflection.Writer;
29 using IKVM.Reflection.Emit;
30
31 namespace IKVM.Reflection
32 {
33         sealed class MethodSignature : Signature
34         {
35                 private readonly Type returnType;
36                 private readonly Type[] parameterTypes;
37                 private readonly PackedCustomModifiers modifiers;
38                 private readonly CallingConventions callingConvention;
39                 private readonly int genericParamCount;
40
41                 internal MethodSignature(Type returnType, Type[] parameterTypes, PackedCustomModifiers modifiers, CallingConventions callingConvention, int genericParamCount)
42                 {
43                         this.returnType = returnType;
44                         this.parameterTypes = parameterTypes;
45                         this.modifiers = modifiers;
46                         this.callingConvention = callingConvention;
47                         this.genericParamCount = genericParamCount;
48                 }
49
50                 public override bool Equals(object obj)
51                 {
52                         MethodSignature other = obj as MethodSignature;
53                         return other != null
54                                 && other.callingConvention == callingConvention
55                                 && other.genericParamCount == genericParamCount
56                                 && other.returnType.Equals(returnType)
57                                 && Util.ArrayEquals(other.parameterTypes, parameterTypes)
58                                 && other.modifiers.Equals(modifiers);
59                 }
60
61                 public override int GetHashCode()
62                 {
63                         return genericParamCount ^ 77 * (int)callingConvention
64                                 ^ 3 * returnType.GetHashCode()
65                                 ^ Util.GetHashCode(parameterTypes) * 5
66                                 ^ modifiers.GetHashCode() * 55;
67                 }
68
69                 private sealed class UnboundGenericMethodContext : IGenericContext
70                 {
71                         private readonly IGenericContext original;
72
73                         internal UnboundGenericMethodContext(IGenericContext original)
74                         {
75                                 this.original = original;
76                         }
77
78                         public Type GetGenericTypeArgument(int index)
79                         {
80                                 return original.GetGenericTypeArgument(index);
81                         }
82
83                         public Type GetGenericMethodArgument(int index)
84                         {
85                                 return UnboundGenericMethodParameter.Make(index);
86                         }
87                 }
88
89                 internal static MethodSignature ReadSig(ModuleReader module, ByteReader br, IGenericContext context)
90                 {
91                         CallingConventions callingConvention;
92                         int genericParamCount;
93                         Type returnType;
94                         Type[] parameterTypes;
95                         byte flags = br.ReadByte();
96                         switch (flags & 7)
97                         {
98                                 case DEFAULT:
99                                         callingConvention = CallingConventions.Standard;
100                                         break;
101                                 case VARARG:
102                                         callingConvention = CallingConventions.VarArgs;
103                                         break;
104                                 default:
105                                         throw new BadImageFormatException();
106                         }
107                         if ((flags & HASTHIS) != 0)
108                         {
109                                 callingConvention |= CallingConventions.HasThis;
110                         }
111                         if ((flags & EXPLICITTHIS) != 0)
112                         {
113                                 callingConvention |= CallingConventions.ExplicitThis;
114                         }
115                         genericParamCount = 0;
116                         if ((flags & GENERIC) != 0)
117                         {
118                                 genericParamCount = br.ReadCompressedInt();
119                                 context = new UnboundGenericMethodContext(context);
120                         }
121                         int paramCount = br.ReadCompressedInt();
122                         CustomModifiers[] modifiers = null;
123                         PackedCustomModifiers.Pack(ref modifiers, 0, CustomModifiers.Read(module, br, context), paramCount + 1);
124                         returnType = ReadRetType(module, br, context);
125                         parameterTypes = new Type[paramCount];
126                         for (int i = 0; i < parameterTypes.Length; i++)
127                         {
128                                 if ((callingConvention & CallingConventions.VarArgs) != 0 && br.PeekByte() == SENTINEL)
129                                 {
130                                         Array.Resize(ref parameterTypes, i);
131                                         if (modifiers != null)
132                                         {
133                                                 Array.Resize(ref modifiers, i + 1);
134                                         }
135                                         break;
136                                 }
137                                 PackedCustomModifiers.Pack(ref modifiers, i + 1, CustomModifiers.Read(module, br, context), paramCount + 1);
138                                 parameterTypes[i] = ReadParam(module, br, context);
139                         }
140                         return new MethodSignature(returnType, parameterTypes, PackedCustomModifiers.Wrap(modifiers), callingConvention, genericParamCount);
141                 }
142
143                 internal static __StandAloneMethodSig ReadStandAloneMethodSig(ModuleReader module, ByteReader br, IGenericContext context)
144                 {
145                         CallingConventions callingConvention = 0;
146                         System.Runtime.InteropServices.CallingConvention unmanagedCallingConvention = 0;
147                         bool unmanaged;
148                         byte flags = br.ReadByte();
149                         switch (flags & 7)
150                         {
151                                 case DEFAULT:
152                                         callingConvention = CallingConventions.Standard;
153                                         unmanaged = false;
154                                         break;
155                                 case 0x01:      // C
156                                         unmanagedCallingConvention = System.Runtime.InteropServices.CallingConvention.Cdecl;
157                                         unmanaged = true;
158                                         break;
159                                 case 0x02:      // STDCALL
160                                         unmanagedCallingConvention = System.Runtime.InteropServices.CallingConvention.StdCall;
161                                         unmanaged = true;
162                                         break;
163                                 case 0x03:      // THISCALL
164                                         unmanagedCallingConvention = System.Runtime.InteropServices.CallingConvention.ThisCall;
165                                         unmanaged = true;
166                                         break;
167                                 case 0x04:      // FASTCALL
168                                         unmanagedCallingConvention = System.Runtime.InteropServices.CallingConvention.FastCall;
169                                         unmanaged = true;
170                                         break;
171                                 case VARARG:
172                                         callingConvention = CallingConventions.VarArgs;
173                                         unmanaged = false;
174                                         break;
175                                 default:
176                                         throw new BadImageFormatException();
177                         }
178                         if ((flags & HASTHIS) != 0)
179                         {
180                                 callingConvention |= CallingConventions.HasThis;
181                         }
182                         if ((flags & EXPLICITTHIS) != 0)
183                         {
184                                 callingConvention |= CallingConventions.ExplicitThis;
185                         }
186                         if ((flags & GENERIC) != 0)
187                         {
188                                 throw new BadImageFormatException();
189                         }
190                         int paramCount = br.ReadCompressedInt();
191                         CustomModifiers[] customModifiers = null;
192                         PackedCustomModifiers.Pack(ref customModifiers, 0, CustomModifiers.Read(module, br, context), paramCount + 1);
193                         Type returnType = ReadRetType(module, br, context);
194                         List<Type> parameterTypes = new List<Type>();
195                         List<Type> optionalParameterTypes = new List<Type>();
196                         List<Type> curr = parameterTypes;
197                         for (int i = 0; i < paramCount; i++)
198                         {
199                                 if (br.PeekByte() == SENTINEL)
200                                 {
201                                         br.ReadByte();
202                                         curr = optionalParameterTypes;
203                                 }
204                                 PackedCustomModifiers.Pack(ref customModifiers, i + 1, CustomModifiers.Read(module, br, context), paramCount + 1);
205                                 curr.Add(ReadParam(module, br, context));
206                         }
207                         return new __StandAloneMethodSig(unmanaged, unmanagedCallingConvention, callingConvention, returnType, parameterTypes.ToArray(), optionalParameterTypes.ToArray(), PackedCustomModifiers.Wrap(customModifiers));
208                 }
209
210                 internal int GetParameterCount()
211                 {
212                         return parameterTypes.Length;
213                 }
214
215                 internal Type GetParameterType(int index)
216                 {
217                         return parameterTypes[index];
218                 }
219
220                 internal Type GetReturnType(IGenericBinder binder)
221                 {
222                         return returnType.BindTypeParameters(binder);
223                 }
224
225                 internal CustomModifiers GetReturnTypeCustomModifiers(IGenericBinder binder)
226                 {
227                         return modifiers.GetReturnTypeCustomModifiers().Bind(binder);
228                 }
229
230                 internal Type GetParameterType(IGenericBinder binder, int index)
231                 {
232                         return parameterTypes[index].BindTypeParameters(binder);
233                 }
234
235                 internal CustomModifiers GetParameterCustomModifiers(IGenericBinder binder, int index)
236                 {
237                         return modifiers.GetParameterCustomModifiers(index).Bind(binder);
238                 }
239
240                 internal CallingConventions CallingConvention
241                 {
242                         get { return callingConvention; }
243                 }
244
245                 internal int GenericParameterCount
246                 {
247                         get { return genericParamCount; }
248                 }
249
250                 private sealed class Binder : IGenericBinder
251                 {
252                         private readonly Type declaringType;
253                         private readonly Type[] methodArgs;
254
255                         internal Binder(Type declaringType, Type[] methodArgs)
256                         {
257                                 this.declaringType = declaringType;
258                                 this.methodArgs = methodArgs;
259                         }
260
261                         public Type BindTypeParameter(Type type)
262                         {
263                                 return declaringType.GetGenericTypeArgument(type.GenericParameterPosition);
264                         }
265
266                         public Type BindMethodParameter(Type type)
267                         {
268                                 if (methodArgs == null)
269                                 {
270                                         return type;
271                                 }
272                                 return methodArgs[type.GenericParameterPosition];
273                         }
274                 }
275
276                 internal MethodSignature Bind(Type type, Type[] methodArgs)
277                 {
278                         Binder binder = new Binder(type, methodArgs);
279                         return new MethodSignature(returnType.BindTypeParameters(binder),
280                                 BindTypeParameters(binder, parameterTypes),
281                                 modifiers.Bind(binder),
282                                 callingConvention, genericParamCount);
283                 }
284
285                 private sealed class Unbinder : IGenericBinder
286                 {
287                         internal static readonly Unbinder Instance = new Unbinder();
288
289                         private Unbinder()
290                         {
291                         }
292
293                         public Type BindTypeParameter(Type type)
294                         {
295                                 return type;
296                         }
297
298                         public Type BindMethodParameter(Type type)
299                         {
300                                 return UnboundGenericMethodParameter.Make(type.GenericParameterPosition);
301                         }
302                 }
303
304                 internal static MethodSignature MakeFromBuilder(Type returnType, Type[] parameterTypes, PackedCustomModifiers modifiers, CallingConventions callingConvention, int genericParamCount)
305                 {
306                         if (genericParamCount > 0)
307                         {
308                                 returnType = returnType.BindTypeParameters(Unbinder.Instance);
309                                 parameterTypes = BindTypeParameters(Unbinder.Instance, parameterTypes);
310                                 modifiers = modifiers.Bind(Unbinder.Instance);
311                         }
312                         return new MethodSignature(returnType, parameterTypes, modifiers, callingConvention, genericParamCount);
313                 }
314
315                 internal bool MatchParameterTypes(MethodSignature other)
316                 {
317                         return Util.ArrayEquals(other.parameterTypes, parameterTypes);
318                 }
319
320                 internal bool MatchParameterTypes(Type[] types)
321                 {
322                         return Util.ArrayEquals(types, parameterTypes);
323                 }
324
325                 internal override void WriteSig(ModuleBuilder module, ByteBuffer bb)
326                 {
327                         WriteSigImpl(module, bb, parameterTypes.Length);
328                 }
329
330                 internal void WriteMethodRefSig(ModuleBuilder module, ByteBuffer bb, Type[] optionalParameterTypes, CustomModifiers[] customModifiers)
331                 {
332                         WriteSigImpl(module, bb, parameterTypes.Length + optionalParameterTypes.Length);
333                         if (optionalParameterTypes.Length > 0)
334                         {
335                                 bb.Write(SENTINEL);
336                                 for (int i = 0; i < optionalParameterTypes.Length; i++)
337                                 {
338                                         WriteCustomModifiers(module, bb, Util.NullSafeElementAt(customModifiers, i));
339                                         WriteType(module, bb, optionalParameterTypes[i]);
340                                 }
341                         }
342                 }
343
344                 private void WriteSigImpl(ModuleBuilder module, ByteBuffer bb, int parameterCount)
345                 {
346                         byte first;
347                         if ((callingConvention & CallingConventions.Any) == CallingConventions.VarArgs)
348                         {
349                                 Debug.Assert(genericParamCount == 0);
350                                 first = VARARG;
351                         }
352                         else if (genericParamCount > 0)
353                         {
354                                 first = GENERIC;
355                         }
356                         else
357                         {
358                                 first = DEFAULT;
359                         }
360                         if ((callingConvention & CallingConventions.HasThis) != 0)
361                         {
362                                 first |= HASTHIS;
363                         }
364                         if ((callingConvention & CallingConventions.ExplicitThis) != 0)
365                         {
366                                 first |= EXPLICITTHIS;
367                         }
368                         bb.Write(first);
369                         if (genericParamCount > 0)
370                         {
371                                 bb.WriteCompressedInt(genericParamCount);
372                         }
373                         bb.WriteCompressedInt(parameterCount);
374                         // RetType
375                         WriteCustomModifiers(module, bb, modifiers.GetReturnTypeCustomModifiers());
376                         WriteType(module, bb, returnType);
377                         // Param
378                         for (int i = 0; i < parameterTypes.Length; i++)
379                         {
380                                 WriteCustomModifiers(module, bb, modifiers.GetParameterCustomModifiers(i));
381                                 WriteType(module, bb, parameterTypes[i]);
382                         }
383                 }
384         }
385
386         struct PackedCustomModifiers
387         {
388                 // element 0 is the return type, the rest are the parameters
389                 private readonly CustomModifiers[] customModifiers;
390
391                 private PackedCustomModifiers(CustomModifiers[] customModifiers)
392                 {
393                         this.customModifiers = customModifiers;
394                 }
395
396                 public override int GetHashCode()
397                 {
398                         return Util.GetHashCode(customModifiers);
399                 }
400
401                 public override bool Equals(object obj)
402                 {
403                         PackedCustomModifiers? other = obj as PackedCustomModifiers?;
404                         return other != null && Equals(other.Value);
405                 }
406
407                 internal bool Equals(PackedCustomModifiers other)
408                 {
409                         return Util.ArrayEquals(customModifiers, other.customModifiers);
410                 }
411
412                 internal CustomModifiers GetReturnTypeCustomModifiers()
413                 {
414                         if (customModifiers == null)
415                         {
416                                 return new CustomModifiers();
417                         }
418                         return customModifiers[0];
419                 }
420
421                 internal CustomModifiers GetParameterCustomModifiers(int index)
422                 {
423                         if (customModifiers == null)
424                         {
425                                 return new CustomModifiers();
426                         }
427                         return customModifiers[index + 1];
428                 }
429
430                 internal PackedCustomModifiers Bind(IGenericBinder binder)
431                 {
432                         if (customModifiers == null)
433                         {
434                                 return new PackedCustomModifiers();
435                         }
436                         CustomModifiers[] expanded = new CustomModifiers[customModifiers.Length];
437                         for (int i = 0; i < customModifiers.Length; i++)
438                         {
439                                 expanded[i] = customModifiers[i].Bind(binder);
440                         }
441                         return new PackedCustomModifiers(expanded);
442                 }
443
444                 // this method make a copy of the incoming arrays (where necessary) and returns a normalized modifiers array
445                 internal static PackedCustomModifiers CreateFromExternal(Type[] returnOptional, Type[] returnRequired, Type[][] parameterOptional, Type[][] parameterRequired, int parameterCount)
446                 {
447                         CustomModifiers[] modifiers = null;
448                         Pack(ref modifiers, 0, CustomModifiers.FromReqOpt(returnRequired, returnOptional), parameterCount + 1);
449                         for (int i = 0; i < parameterCount; i++)
450                         {
451                                 Pack(ref modifiers, i + 1, CustomModifiers.FromReqOpt(Util.NullSafeElementAt(parameterRequired, i), Util.NullSafeElementAt(parameterOptional, i)), parameterCount + 1);
452                         }
453                         return new PackedCustomModifiers(modifiers);
454                 }
455
456                 internal static PackedCustomModifiers CreateFromExternal(CustomModifiers returnTypeCustomModifiers, CustomModifiers[] parameterTypeCustomModifiers, int parameterCount)
457                 {
458                         CustomModifiers[] customModifiers = null;
459                         Pack(ref customModifiers, 0, returnTypeCustomModifiers, parameterCount + 1);
460                         if (parameterTypeCustomModifiers != null)
461                         {
462                                 for (int i = 0; i < parameterCount; i++)
463                                 {
464                                         Pack(ref customModifiers, i + 1, parameterTypeCustomModifiers[i], parameterCount + 1);
465                                 }
466                         }
467                         return new PackedCustomModifiers(customModifiers);
468                 }
469
470                 internal static PackedCustomModifiers Wrap(CustomModifiers[] modifiers)
471                 {
472                         return new PackedCustomModifiers(modifiers);
473                 }
474
475                 internal static void Pack(ref CustomModifiers[] array, int index, CustomModifiers mods, int count)
476                 {
477                         if (!mods.IsEmpty)
478                         {
479                                 if (array == null)
480                                 {
481                                         array = new CustomModifiers[count];
482                                 }
483                                 array[index] = mods;
484                         }
485                 }
486         }
487 }