do not check order sequence if option /order was not used
[mono.git] / mcs / class / IKVM.Reflection / Emit / SignatureHelper.cs
1 /*
2   Copyright (C) 2008-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.Runtime.InteropServices;
27 using IKVM.Reflection;
28 using IKVM.Reflection.Writer;
29
30 namespace IKVM.Reflection.Emit
31 {
32         public abstract class SignatureHelper
33         {
34                 protected readonly byte type;
35                 protected ushort paramCount;
36
37                 sealed class Lazy : SignatureHelper
38                 {
39                         private readonly List<Type> args = new List<Type>();
40
41                         internal Lazy(byte type)
42                                 : base(type)
43                         {
44                         }
45
46                         internal override Type ReturnType
47                         {
48                                 get { return args[0]; }
49                         }
50
51                         public override byte[] GetSignature()
52                         {
53                                 throw new NotSupportedException();
54                         }
55
56                         internal override ByteBuffer GetSignature(ModuleBuilder module)
57                         {
58                                 ByteBuffer bb = new ByteBuffer(16);
59                                 Signature.WriteSignatureHelper(module, bb, type, paramCount, args);
60                                 return bb;
61                         }
62
63                         public override void AddSentinel()
64                         {
65                                 args.Add(MarkerType.Sentinel);
66                         }
67
68                         public override void __AddArgument(Type argument, bool pinned, CustomModifiers customModifiers)
69                         {
70                                 if (pinned)
71                                 {
72                                         args.Add(MarkerType.Pinned);
73                                 }
74                                 foreach (CustomModifiers.Entry mod in customModifiers)
75                                 {
76                                         args.Add(mod.IsRequired ? MarkerType.ModReq : MarkerType.ModOpt);
77                                         args.Add(mod.Type);
78                                 }
79                                 args.Add(argument);
80                                 paramCount++;
81                         }
82                 }
83
84                 sealed class Eager : SignatureHelper
85                 {
86                         private readonly ModuleBuilder module;
87                         private readonly ByteBuffer bb = new ByteBuffer(16);
88                         private readonly Type returnType;
89
90                         internal Eager(ModuleBuilder module, byte type, Type returnType)
91                                 : base(type)
92                         {
93                                 this.module = module;
94                                 this.returnType = returnType;
95                                 bb.Write(type);
96                                 if (type != Signature.FIELD)
97                                 {
98                                         // space for parameterCount
99                                         bb.Write((byte)0);
100                                 }
101                         }
102
103                         internal override Type ReturnType
104                         {
105                                 get { return returnType; }
106                         }
107
108                         public override byte[] GetSignature()
109                         {
110                                 return GetSignature(null).ToArray();
111                         }
112
113                         internal override ByteBuffer GetSignature(ModuleBuilder module)
114                         {
115                                 if (type != Signature.FIELD)
116                                 {
117                                         bb.Position = 1;
118                                         bb.Insert(MetadataWriter.GetCompressedIntLength(paramCount) - bb.GetCompressedIntLength());
119                                         bb.WriteCompressedInt(paramCount);
120                                 }
121                                 return bb;
122                         }
123
124                         public override void AddSentinel()
125                         {
126                                 bb.Write(Signature.SENTINEL);
127                         }
128
129                         public override void __AddArgument(Type argument, bool pinned, CustomModifiers customModifiers)
130                         {
131                                 if (pinned)
132                                 {
133                                         bb.Write(Signature.ELEMENT_TYPE_PINNED);
134                                 }
135                                 foreach (CustomModifiers.Entry mod in customModifiers)
136                                 {
137                                         bb.Write(mod.IsRequired ? Signature.ELEMENT_TYPE_CMOD_REQD : Signature.ELEMENT_TYPE_CMOD_OPT);
138                                         Signature.WriteTypeSpec(module, bb, mod.Type);
139                                 }
140                                 Signature.WriteTypeSpec(module, bb, argument ?? module.universe.System_Void);
141                                 paramCount++;
142                         }
143                 }
144
145                 private SignatureHelper(byte type)
146                 {
147                         this.type = type;
148                 }
149
150                 internal bool HasThis
151                 {
152                         get { return (type & Signature.HASTHIS) != 0; }
153                 }
154
155                 internal abstract Type ReturnType
156                 {
157                         get;
158                 }
159
160                 internal int ParameterCount
161                 {
162                         get { return paramCount; }
163                 }
164
165                 private static SignatureHelper Create(Module mod, byte type, Type returnType)
166                 {
167                         ModuleBuilder mb = mod as ModuleBuilder;
168                         return mb == null
169                                 ? (SignatureHelper)new Lazy(type)
170                                 : new Eager(mb, type, returnType);
171                 }
172
173                 public static SignatureHelper GetFieldSigHelper(Module mod)
174                 {
175                         return Create(mod, Signature.FIELD, null);
176                 }
177
178                 public static SignatureHelper GetLocalVarSigHelper()
179                 {
180                         return new Lazy(Signature.LOCAL_SIG);
181                 }
182
183                 public static SignatureHelper GetLocalVarSigHelper(Module mod)
184                 {
185                         return Create(mod, Signature.LOCAL_SIG, null);
186                 }
187
188                 public static SignatureHelper GetPropertySigHelper(Module mod, Type returnType, Type[] parameterTypes)
189                 {
190                         SignatureHelper sig = Create(mod, Signature.PROPERTY, returnType);
191                         sig.AddArgument(returnType);
192                         sig.paramCount = 0;
193                         sig.AddArguments(parameterTypes, null, null);
194                         return sig;
195                 }
196
197                 public static SignatureHelper GetPropertySigHelper(Module mod, Type returnType, Type[] requiredReturnTypeCustomModifiers, Type[] optionalReturnTypeCustomModifiers, Type[] parameterTypes, Type[][] requiredParameterTypeCustomModifiers, Type[][] optionalParameterTypeCustomModifiers)
198                 {
199                         return GetPropertySigHelper(mod, CallingConventions.Standard, returnType, requiredReturnTypeCustomModifiers, optionalReturnTypeCustomModifiers, parameterTypes, requiredParameterTypeCustomModifiers, optionalParameterTypeCustomModifiers);
200                 }
201
202                 public static SignatureHelper GetPropertySigHelper(Module mod, CallingConventions callingConvention, Type returnType, Type[] requiredReturnTypeCustomModifiers, Type[] optionalReturnTypeCustomModifiers, Type[] parameterTypes, Type[][] requiredParameterTypeCustomModifiers, Type[][] optionalParameterTypeCustomModifiers)
203                 {
204                         byte type = Signature.PROPERTY;
205                         if ((callingConvention & CallingConventions.HasThis) != 0)
206                         {
207                                 type |= Signature.HASTHIS;
208                         }
209                         SignatureHelper sig = Create(mod, type, returnType);
210                         sig.AddArgument(returnType, requiredReturnTypeCustomModifiers, optionalReturnTypeCustomModifiers);
211                         sig.paramCount = 0;
212                         sig.AddArguments(parameterTypes, requiredParameterTypeCustomModifiers, optionalParameterTypeCustomModifiers);
213                         return sig;
214                 }
215
216                 public static SignatureHelper GetMethodSigHelper(CallingConvention unmanagedCallingConvention, Type returnType)
217                 {
218                         return GetMethodSigHelper(null, unmanagedCallingConvention, returnType);
219                 }
220
221                 public static SignatureHelper GetMethodSigHelper(CallingConventions callingConvention, Type returnType)
222                 {
223                         return GetMethodSigHelper(null, callingConvention, returnType);
224                 }
225
226                 public static SignatureHelper GetMethodSigHelper(Module mod, CallingConvention unmanagedCallConv, Type returnType)
227                 {
228                         byte type;
229                         switch (unmanagedCallConv)
230                         {
231                                 case CallingConvention.Cdecl:
232                                         type = 0x01;    // C
233                                         break;
234                                 case CallingConvention.StdCall:
235                                 case CallingConvention.Winapi:
236                                         type = 0x02;    // STDCALL
237                                         break;
238                                 case CallingConvention.ThisCall:
239                                         type = 0x03;    // THISCALL
240                                         break;
241                                 case CallingConvention.FastCall:
242                                         type = 0x04;    // FASTCALL
243                                         break;
244                                 default:
245                                         throw new ArgumentOutOfRangeException("unmanagedCallConv");
246                         }
247                         SignatureHelper sig = Create(mod, type, returnType);
248                         sig.AddArgument(returnType);
249                         sig.paramCount = 0;
250                         return sig;
251                 }
252
253                 public static SignatureHelper GetMethodSigHelper(Module mod, CallingConventions callingConvention, Type returnType)
254                 {
255                         byte type = 0;
256                         if ((callingConvention & CallingConventions.HasThis) != 0)
257                         {
258                                 type |= Signature.HASTHIS;
259                         }
260                         if ((callingConvention & CallingConventions.ExplicitThis) != 0)
261                         {
262                                 type |= Signature.EXPLICITTHIS;
263                         }
264                         if ((callingConvention & CallingConventions.VarArgs) != 0)
265                         {
266                                 type |= Signature.VARARG;
267                         }
268                         SignatureHelper sig = Create(mod, type, returnType);
269                         sig.AddArgument(returnType);
270                         sig.paramCount = 0;
271                         return sig;
272                 }
273
274                 public static SignatureHelper GetMethodSigHelper(Module mod, Type returnType, Type[] parameterTypes)
275                 {
276                         SignatureHelper sig = Create(mod, 0, returnType);
277                         sig.AddArgument(returnType);
278                         sig.paramCount = 0;
279                         sig.AddArguments(parameterTypes, null, null);
280                         return sig;
281                 }
282
283                 public abstract byte[] GetSignature();
284
285                 internal abstract ByteBuffer GetSignature(ModuleBuilder module);
286
287                 public abstract void AddSentinel();
288
289                 public void AddArgument(Type clsArgument)
290                 {
291                         AddArgument(clsArgument, false);
292                 }
293
294                 public void AddArgument(Type argument, bool pinned)
295                 {
296                         __AddArgument(argument, pinned, new CustomModifiers());
297                 }
298
299                 public void AddArgument(Type argument, Type[] requiredCustomModifiers, Type[] optionalCustomModifiers)
300                 {
301                         __AddArgument(argument, false, CustomModifiers.FromReqOpt(requiredCustomModifiers, optionalCustomModifiers));
302                 }
303
304                 public abstract void __AddArgument(Type argument, bool pinned, CustomModifiers customModifiers);
305
306                 public void AddArguments(Type[] arguments, Type[][] requiredCustomModifiers, Type[][] optionalCustomModifiers)
307                 {
308                         if (arguments != null)
309                         {
310                                 for (int i = 0; i < arguments.Length; i++)
311                                 {
312                                         __AddArgument(arguments[i], false, CustomModifiers.FromReqOpt(Util.NullSafeElementAt(requiredCustomModifiers, i), Util.NullSafeElementAt(optionalCustomModifiers, i)));
313                                 }
314                         }
315                 }
316         }
317 }