2 Copyright (C) 2009 Jeroen Frijters
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.
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:
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.
25 using System.Collections.Generic;
27 using IKVM.Reflection.Metadata;
29 namespace IKVM.Reflection.Reader
31 sealed class MethodDefImpl : MethodInfo
33 private readonly ModuleReader module;
34 private readonly int index;
35 private readonly TypeDefImpl declaringType;
36 private MethodSignature lazyMethodSignature;
37 private ParameterInfo returnParameter;
38 private ParameterInfo[] parameters;
39 private Type[] typeArgs;
41 internal MethodDefImpl(ModuleReader module, TypeDefImpl declaringType, int index)
45 this.declaringType = declaringType;
48 public override MethodBody GetMethodBody()
50 return GetMethodBody(this);
53 internal MethodBody GetMethodBody(IGenericContext context)
55 if ((GetMethodImplementationFlags() & MethodImplAttributes.CodeTypeMask) != MethodImplAttributes.IL)
60 int rva = module.MethodDef.records[index].RVA;
61 return rva == 0 ? null : new MethodBody(module, rva, context);
64 public override CallingConventions CallingConvention
66 get { return this.MethodSignature.CallingConvention; }
69 public override MethodAttributes Attributes
71 get { return (MethodAttributes)module.MethodDef.records[index].Flags; }
74 public override MethodImplAttributes GetMethodImplementationFlags()
76 return (MethodImplAttributes)module.MethodDef.records[index].ImplFlags;
79 public override ParameterInfo[] GetParameters()
82 return (ParameterInfo[])parameters.Clone();
85 private void PopulateParameters()
87 if (parameters == null)
89 MethodSignature methodSignature = this.MethodSignature;
90 parameters = new ParameterInfo[methodSignature.GetParameterCount()];
91 int parameter = module.MethodDef.records[index].ParamList - 1;
92 int end = module.MethodDef.records.Length > index + 1 ? module.MethodDef.records[index + 1].ParamList - 1 : module.Param.records.Length;
93 for (; parameter < end; parameter++)
95 int seq = module.Param.records[parameter].Sequence - 1;
98 returnParameter = new ParameterInfoImpl(this, seq, parameter);
102 parameters[seq] = new ParameterInfoImpl(this, seq, parameter);
105 for (int i = 0; i < parameters.Length; i++)
107 if (parameters[i] == null)
109 parameters[i] = new ParameterInfoImpl(this, i, -1);
112 if (returnParameter == null)
114 returnParameter = new ParameterInfoImpl(this, -1, -1);
119 internal override int ParameterCount
121 get { return this.MethodSignature.GetParameterCount(); }
124 public override ParameterInfo ReturnParameter
128 PopulateParameters();
129 return returnParameter;
133 public override Type ReturnType
137 return this.ReturnParameter.ParameterType;
141 public override Type DeclaringType
143 get { return declaringType.IsModulePseudoType ? null : declaringType; }
146 public override string Name
148 get { return module.GetString(module.MethodDef.records[index].Name); }
151 public override int MetadataToken
153 get { return (MethodDefTable.Index << 24) + index + 1; }
156 public override bool IsGenericMethodDefinition
160 PopulateGenericArguments();
161 return typeArgs.Length > 0;
165 public override bool IsGenericMethod
167 get { return IsGenericMethodDefinition; }
170 public override Type[] GetGenericArguments()
172 PopulateGenericArguments();
173 return Util.Copy(typeArgs);
176 private void PopulateGenericArguments()
178 if (typeArgs == null)
180 int token = this.MetadataToken;
181 int first = module.GenericParam.FindFirstByOwner(token);
184 typeArgs = Type.EmptyTypes;
188 List<Type> list = new List<Type>();
189 int len = module.GenericParam.records.Length;
190 for (int i = first; i < len && module.GenericParam.records[i].Owner == token; i++)
192 list.Add(new GenericTypeParameter(module, i));
194 typeArgs = list.ToArray();
199 internal override Type GetGenericMethodArgument(int index)
201 PopulateGenericArguments();
202 return typeArgs[index];
205 internal override int GetGenericMethodArgumentCount()
207 PopulateGenericArguments();
208 return typeArgs.Length;
211 public override MethodInfo GetGenericMethodDefinition()
213 if (this.IsGenericMethodDefinition)
217 throw new InvalidOperationException();
220 public override MethodInfo MakeGenericMethod(params Type[] typeArguments)
222 return new GenericMethodInstance(declaringType, this, typeArguments);
225 public override Module Module
227 get { return module; }
230 internal override IList<CustomAttributeData> GetCustomAttributesData(Type attributeType)
232 List<CustomAttributeData> list = module.GetCustomAttributes(this.MetadataToken, attributeType);
233 if ((this.Attributes & MethodAttributes.PinvokeImpl) != 0
234 && (attributeType == null || attributeType.IsAssignableFrom(module.universe.System_Runtime_InteropServices_DllImportAttribute)))
236 CreateDllImportPseudoCustomAttribute(list);
241 private void CreateDllImportPseudoCustomAttribute(List<CustomAttributeData> attribs)
243 int token = this.MetadataToken;
244 // TODO use binary search?
245 for (int i = 0; i < module.ImplMap.records.Length; i++)
247 if (module.ImplMap.records[i].MemberForwarded == token)
249 const short NoMangle = 0x0001;
250 const short CharSetMask = 0x0006;
251 const short CharSetNotSpec = 0x0000;
252 const short CharSetAnsi = 0x0002;
253 const short CharSetUnicode = 0x0004;
254 const short CharSetAuto = 0x0006;
255 const short SupportsLastError = 0x0040;
256 const short CallConvMask = 0x0700;
257 const short CallConvWinapi = 0x0100;
258 const short CallConvCdecl = 0x0200;
259 const short CallConvStdcall = 0x0300;
260 const short CallConvThiscall = 0x0400;
261 const short CallConvFastcall = 0x0500;
262 // non-standard flags
263 const short BestFitOn = 0x0010;
264 const short BestFitOff = 0x0020;
265 const short CharMapErrorOn = 0x1000;
266 const short CharMapErrorOff = 0x2000;
268 Type type = module.universe.System_Runtime_InteropServices_DllImportAttribute;
269 ConstructorInfo constructor = type.GetConstructor(new Type[] { module.universe.System_String });
270 List<CustomAttributeNamedArgument> list = new List<CustomAttributeNamedArgument>();
271 int flags = module.ImplMap.records[i].MappingFlags;
272 string entryPoint = module.GetString(module.ImplMap.records[i].ImportName);
273 string dllName = module.GetString(module.ModuleRef.records[(module.ImplMap.records[i].ImportScope & 0xFFFFFF) - 1]);
274 System.Runtime.InteropServices.CharSet? charSet;
275 switch (flags & CharSetMask)
278 charSet = System.Runtime.InteropServices.CharSet.Ansi;
281 charSet = System.Runtime.InteropServices.CharSet.Unicode;
284 charSet = System.Runtime.InteropServices.CharSet.Auto;
291 System.Runtime.InteropServices.CallingConvention callingConvention;
292 switch (flags & CallConvMask)
295 callingConvention = System.Runtime.InteropServices.CallingConvention.Cdecl;
297 case CallConvFastcall:
298 callingConvention = System.Runtime.InteropServices.CallingConvention.FastCall;
300 case CallConvStdcall:
301 callingConvention = System.Runtime.InteropServices.CallingConvention.StdCall;
303 case CallConvThiscall:
304 callingConvention = System.Runtime.InteropServices.CallingConvention.ThisCall;
308 callingConvention = System.Runtime.InteropServices.CallingConvention.Winapi;
311 list.Add(MakeNamedArgument(type, "EntryPoint", entryPoint));
312 list.Add(MakeNamedArgument(type, "ExactSpelling", flags, NoMangle));
313 list.Add(MakeNamedArgument(type, "SetLastError", flags, SupportsLastError));
314 list.Add(MakeNamedArgument(type, "PreserveSig", (int)GetMethodImplementationFlags(), (int)MethodImplAttributes.PreserveSig));
315 list.Add(MakeNamedArgument(type, "CallingConvention", (int)callingConvention));
316 if (charSet.HasValue)
318 list.Add(MakeNamedArgument(type, "CharSet", (int)charSet.Value));
320 if ((flags & (BestFitOn | BestFitOff)) != 0)
322 list.Add(MakeNamedArgument(type, "BestFitMapping", flags, BestFitOn));
324 if ((flags & (CharMapErrorOn | CharMapErrorOff)) != 0)
326 list.Add(MakeNamedArgument(type, "ThrowOnUnmappableChar", flags, CharMapErrorOn));
328 attribs.Add(new CustomAttributeData(constructor, new object[] { dllName }, list));
334 private static CustomAttributeNamedArgument MakeNamedArgument(Type type, string field, string value)
336 return new CustomAttributeNamedArgument(type.GetField(field), new CustomAttributeTypedArgument(type.Module.universe.System_String, value));
339 private static CustomAttributeNamedArgument MakeNamedArgument(Type type, string field, int value)
341 return new CustomAttributeNamedArgument(type.GetField(field), new CustomAttributeTypedArgument(type.Module.universe.System_Int32, value));
344 private static CustomAttributeNamedArgument MakeNamedArgument(Type type, string field, int flags, int flagMask)
346 return new CustomAttributeNamedArgument(type.GetField(field), new CustomAttributeTypedArgument(type.Module.universe.System_Boolean, (flags & flagMask) != 0));
349 internal override MethodSignature MethodSignature
351 get { return lazyMethodSignature ?? (lazyMethodSignature = MethodSignature.ReadSig(module, module.GetBlob(module.MethodDef.records[index].Signature), this)); }
354 internal override int ImportTo(Emit.ModuleBuilder module)
356 return module.ImportMethodOrField(declaringType, this.Name, this.MethodSignature);
360 sealed class ParameterInfoImpl : ParameterInfo
362 private readonly MethodDefImpl method;
363 private readonly int position;
364 private readonly int index;
366 internal ParameterInfoImpl(MethodDefImpl method, int position, int index)
368 this.method = method;
369 this.position = position;
373 public override string Name
375 get { return index == -1 ? null : ((ModuleReader)this.Module).GetString(this.Module.Param.records[index].Name); }
378 public override Type ParameterType
380 get { return position == -1 ? method.MethodSignature.GetReturnType(method) : method.MethodSignature.GetParameterType(method, position); }
383 public override ParameterAttributes Attributes
385 get { return index == -1 ? ParameterAttributes.None : (ParameterAttributes)this.Module.Param.records[index].Flags; }
388 public override int Position
390 get { return position; }
393 public override object RawDefaultValue
397 if ((this.Attributes & ParameterAttributes.HasDefault) != 0)
399 return this.Module.Constant.GetRawConstantValue(this.Module, this.MetadataToken);
401 Universe universe = this.Module.universe;
402 if (this.ParameterType == universe.System_Decimal)
404 Type attr = universe.System_Runtime_CompilerServices_DecimalConstantAttribute;
407 foreach (CustomAttributeData cad in GetCustomAttributesData(attr))
409 IList<CustomAttributeTypedArgument> args = cad.ConstructorArguments;
412 if (args[0].ArgumentType == universe.System_Byte
413 && args[1].ArgumentType == universe.System_Byte
414 && args[2].ArgumentType == universe.System_Int32
415 && args[3].ArgumentType == universe.System_Int32
416 && args[4].ArgumentType == universe.System_Int32)
418 return new Decimal((int)args[4].Value, (int)args[3].Value, (int)args[2].Value, (byte)args[1].Value != 0, (byte)args[0].Value);
420 else if (args[0].ArgumentType == universe.System_Byte
421 && args[1].ArgumentType == universe.System_Byte
422 && args[2].ArgumentType == universe.System_UInt32
423 && args[3].ArgumentType == universe.System_UInt32
424 && args[4].ArgumentType == universe.System_UInt32)
426 return new Decimal(unchecked((int)(uint)args[4].Value), unchecked((int)(uint)args[3].Value), unchecked((int)(uint)args[2].Value), (byte)args[1].Value != 0, (byte)args[0].Value);
432 if ((this.Attributes & ParameterAttributes.Optional) != 0)
434 return Missing.Value;
440 public override Type[] GetRequiredCustomModifiers()
442 return Util.Copy(position == -1 ? method.MethodSignature.GetReturnTypeRequiredCustomModifiers(method) : method.MethodSignature.GetParameterRequiredCustomModifiers(method, position));
445 public override Type[] GetOptionalCustomModifiers()
447 return Util.Copy(position == -1 ? method.MethodSignature.GetReturnTypeOptionalCustomModifiers(method) : method.MethodSignature.GetParameterOptionalCustomModifiers(method, position));
450 public override MemberInfo Member
454 // return the right ConstructorInfo wrapper
455 return method.Module.ResolveMethod(method.MetadataToken);
459 public override int MetadataToken
463 // for parameters that don't have a row in the Param table, we return 0x08000000 (because index is -1 in that case),
465 return (ParamTable.Index << 24) + index + 1;
469 internal override Module Module
471 get { return method.Module; }
474 internal override IList<CustomAttributeData> GetCustomAttributesData(Type attributeType)
476 IList<CustomAttributeData> list = base.GetCustomAttributesData(attributeType);
477 if ((this.Attributes & ParameterAttributes.HasFieldMarshal) != 0
478 && (attributeType == null || attributeType.IsAssignableFrom(this.Module.universe.System_Runtime_InteropServices_MarshalAsAttribute)))
480 list.Add(MarshalSpec.GetMarshalAsAttribute(this.Module, this.MetadataToken));