2 Copyright (C) 2009-2012 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 int __MethodRVA
66 get { return module.MethodDef.records[index].RVA; }
69 public override CallingConventions CallingConvention
71 get { return this.MethodSignature.CallingConvention; }
74 public override MethodAttributes Attributes
76 get { return (MethodAttributes)module.MethodDef.records[index].Flags; }
79 public override MethodImplAttributes GetMethodImplementationFlags()
81 return (MethodImplAttributes)module.MethodDef.records[index].ImplFlags;
84 public override ParameterInfo[] GetParameters()
87 return (ParameterInfo[])parameters.Clone();
90 private void PopulateParameters()
92 if (parameters == null)
94 MethodSignature methodSignature = this.MethodSignature;
95 parameters = new ParameterInfo[methodSignature.GetParameterCount()];
96 int parameter = module.MethodDef.records[index].ParamList - 1;
97 int end = module.MethodDef.records.Length > index + 1 ? module.MethodDef.records[index + 1].ParamList - 1 : module.Param.records.Length;
98 for (; parameter < end; parameter++)
100 int seq = module.Param.records[parameter].Sequence - 1;
103 returnParameter = new ParameterInfoImpl(this, seq, parameter);
107 parameters[seq] = new ParameterInfoImpl(this, seq, parameter);
110 for (int i = 0; i < parameters.Length; i++)
112 if (parameters[i] == null)
114 parameters[i] = new ParameterInfoImpl(this, i, -1);
117 if (returnParameter == null)
119 returnParameter = new ParameterInfoImpl(this, -1, -1);
124 internal override int ParameterCount
126 get { return this.MethodSignature.GetParameterCount(); }
129 public override ParameterInfo ReturnParameter
133 PopulateParameters();
134 return returnParameter;
138 public override Type ReturnType
142 return this.ReturnParameter.ParameterType;
146 public override Type DeclaringType
148 get { return declaringType.IsModulePseudoType ? null : declaringType; }
151 public override string Name
153 get { return module.GetString(module.MethodDef.records[index].Name); }
156 public override int MetadataToken
158 get { return (MethodDefTable.Index << 24) + index + 1; }
161 public override bool IsGenericMethodDefinition
165 PopulateGenericArguments();
166 return typeArgs.Length > 0;
170 public override bool IsGenericMethod
172 get { return IsGenericMethodDefinition; }
175 public override Type[] GetGenericArguments()
177 PopulateGenericArguments();
178 return Util.Copy(typeArgs);
181 private void PopulateGenericArguments()
183 if (typeArgs == null)
185 int token = this.MetadataToken;
186 int first = module.GenericParam.FindFirstByOwner(token);
189 typeArgs = Type.EmptyTypes;
193 List<Type> list = new List<Type>();
194 int len = module.GenericParam.records.Length;
195 for (int i = first; i < len && module.GenericParam.records[i].Owner == token; i++)
197 list.Add(new GenericTypeParameter(module, i));
199 typeArgs = list.ToArray();
204 internal override Type GetGenericMethodArgument(int index)
206 PopulateGenericArguments();
207 return typeArgs[index];
210 internal override int GetGenericMethodArgumentCount()
212 PopulateGenericArguments();
213 return typeArgs.Length;
216 public override MethodInfo GetGenericMethodDefinition()
218 if (this.IsGenericMethodDefinition)
222 throw new InvalidOperationException();
225 public override MethodInfo MakeGenericMethod(params Type[] typeArguments)
227 return new GenericMethodInstance(declaringType, this, typeArguments);
230 public override Module Module
232 get { return module; }
235 internal override IList<CustomAttributeData> GetCustomAttributesData(Type attributeType)
237 List<CustomAttributeData> list = module.GetCustomAttributes(this.MetadataToken, attributeType);
238 if ((this.Attributes & MethodAttributes.PinvokeImpl) != 0
239 && (attributeType == null || attributeType.IsAssignableFrom(module.universe.System_Runtime_InteropServices_DllImportAttribute)))
241 CreateDllImportPseudoCustomAttribute(list);
246 private void CreateDllImportPseudoCustomAttribute(List<CustomAttributeData> attribs)
248 foreach (int i in module.ImplMap.Filter(this.MetadataToken))
250 const short NoMangle = 0x0001;
251 const short CharSetMask = 0x0006;
252 const short CharSetNotSpec = 0x0000;
253 const short CharSetAnsi = 0x0002;
254 const short CharSetUnicode = 0x0004;
255 const short CharSetAuto = 0x0006;
256 const short SupportsLastError = 0x0040;
257 const short CallConvMask = 0x0700;
258 const short CallConvWinapi = 0x0100;
259 const short CallConvCdecl = 0x0200;
260 const short CallConvStdcall = 0x0300;
261 const short CallConvThiscall = 0x0400;
262 const short CallConvFastcall = 0x0500;
263 // non-standard flags
264 const short BestFitOn = 0x0010;
265 const short BestFitOff = 0x0020;
266 const short CharMapErrorOn = 0x1000;
267 const short CharMapErrorOff = 0x2000;
269 Type type = module.universe.System_Runtime_InteropServices_DllImportAttribute;
270 ConstructorInfo constructor = type.GetPseudoCustomAttributeConstructor(module.universe.System_String);
271 List<CustomAttributeNamedArgument> list = new List<CustomAttributeNamedArgument>();
272 int flags = module.ImplMap.records[i].MappingFlags;
273 string entryPoint = module.GetString(module.ImplMap.records[i].ImportName);
274 string dllName = module.GetString(module.ModuleRef.records[(module.ImplMap.records[i].ImportScope & 0xFFFFFF) - 1]);
275 System.Runtime.InteropServices.CharSet? charSet;
276 switch (flags & CharSetMask)
279 charSet = System.Runtime.InteropServices.CharSet.Ansi;
282 charSet = System.Runtime.InteropServices.CharSet.Unicode;
285 charSet = System.Runtime.InteropServices.CharSet.Auto;
292 System.Runtime.InteropServices.CallingConvention callingConvention;
293 switch (flags & CallConvMask)
296 callingConvention = System.Runtime.InteropServices.CallingConvention.Cdecl;
298 case CallConvFastcall:
299 callingConvention = System.Runtime.InteropServices.CallingConvention.FastCall;
301 case CallConvStdcall:
302 callingConvention = System.Runtime.InteropServices.CallingConvention.StdCall;
304 case CallConvThiscall:
305 callingConvention = System.Runtime.InteropServices.CallingConvention.ThisCall;
308 callingConvention = System.Runtime.InteropServices.CallingConvention.Winapi;
311 callingConvention = 0;
314 AddNamedArgument(list, type, "EntryPoint", entryPoint);
315 AddNamedArgument(list, type, "ExactSpelling", flags, NoMangle);
316 AddNamedArgument(list, type, "SetLastError", flags, SupportsLastError);
317 AddNamedArgument(list, type, "PreserveSig", (int)GetMethodImplementationFlags(), (int)MethodImplAttributes.PreserveSig);
318 AddNamedArgument(list, type, "CallingConvention", module.universe.System_Runtime_InteropServices_CallingConvention, (int)callingConvention);
319 if (charSet.HasValue)
321 AddNamedArgument(list, type, "CharSet", module.universe.System_Runtime_InteropServices_CharSet, (int)charSet.Value);
323 if ((flags & (BestFitOn | BestFitOff)) != 0)
325 AddNamedArgument(list, type, "BestFitMapping", flags, BestFitOn);
327 if ((flags & (CharMapErrorOn | CharMapErrorOff)) != 0)
329 AddNamedArgument(list, type, "ThrowOnUnmappableChar", flags, CharMapErrorOn);
331 attribs.Add(new CustomAttributeData(module, constructor, new object[] { dllName }, list));
336 private static void AddNamedArgument(List<CustomAttributeNamedArgument> list, Type type, string fieldName, string value)
338 AddNamedArgument(list, type, fieldName, type.Module.universe.System_String, value);
341 private static void AddNamedArgument(List<CustomAttributeNamedArgument> list, Type type, string fieldName, int flags, int flagMask)
343 AddNamedArgument(list, type, fieldName, type.Module.universe.System_Boolean, (flags & flagMask) != 0);
346 private static void AddNamedArgument(List<CustomAttributeNamedArgument> list, Type attributeType, string fieldName, Type valueType, object value)
348 // some fields are not available on the .NET Compact Framework version of DllImportAttribute
349 FieldInfo field = attributeType.FindField(fieldName, FieldSignature.Create(valueType, new CustomModifiers()));
352 list.Add(new CustomAttributeNamedArgument(field, new CustomAttributeTypedArgument(valueType, value)));
356 internal override MethodSignature MethodSignature
358 get { return lazyMethodSignature ?? (lazyMethodSignature = MethodSignature.ReadSig(module, module.GetBlob(module.MethodDef.records[index].Signature), this)); }
361 internal override int ImportTo(Emit.ModuleBuilder module)
363 return module.ImportMethodOrField(declaringType, this.Name, this.MethodSignature);
366 public override MethodInfo[] __GetMethodImpls()
368 Type[] typeArgs = null;
369 List<MethodInfo> list = null;
370 foreach (int i in module.MethodImpl.Filter(declaringType.MetadataToken))
372 if (module.MethodImpl.records[i].MethodBody == this.MetadataToken)
374 if (typeArgs == null)
376 typeArgs = declaringType.GetGenericArguments();
380 list = new List<MethodInfo>();
382 list.Add((MethodInfo)module.ResolveMethod(module.MethodImpl.records[i].MethodDeclaration, typeArgs, null));
385 return Util.ToArray(list, Empty<MethodInfo>.Array);
389 sealed class ParameterInfoImpl : ParameterInfo
391 private readonly MethodDefImpl method;
392 private readonly int position;
393 private readonly int index;
395 internal ParameterInfoImpl(MethodDefImpl method, int position, int index)
397 this.method = method;
398 this.position = position;
402 public override string Name
404 get { return index == -1 ? null : ((ModuleReader)this.Module).GetString(this.Module.Param.records[index].Name); }
407 public override Type ParameterType
409 get { return position == -1 ? method.MethodSignature.GetReturnType(method) : method.MethodSignature.GetParameterType(method, position); }
412 public override ParameterAttributes Attributes
414 get { return index == -1 ? ParameterAttributes.None : (ParameterAttributes)this.Module.Param.records[index].Flags; }
417 public override int Position
419 get { return position; }
422 public override object RawDefaultValue
426 if ((this.Attributes & ParameterAttributes.HasDefault) != 0)
428 return this.Module.Constant.GetRawConstantValue(this.Module, this.MetadataToken);
430 Universe universe = this.Module.universe;
431 if (this.ParameterType == universe.System_Decimal)
433 Type attr = universe.System_Runtime_CompilerServices_DecimalConstantAttribute;
436 foreach (CustomAttributeData cad in GetCustomAttributesData(attr))
438 IList<CustomAttributeTypedArgument> args = cad.ConstructorArguments;
441 if (args[0].ArgumentType == universe.System_Byte
442 && args[1].ArgumentType == universe.System_Byte
443 && args[2].ArgumentType == universe.System_Int32
444 && args[3].ArgumentType == universe.System_Int32
445 && args[4].ArgumentType == universe.System_Int32)
447 return new Decimal((int)args[4].Value, (int)args[3].Value, (int)args[2].Value, (byte)args[1].Value != 0, (byte)args[0].Value);
449 else if (args[0].ArgumentType == universe.System_Byte
450 && args[1].ArgumentType == universe.System_Byte
451 && args[2].ArgumentType == universe.System_UInt32
452 && args[3].ArgumentType == universe.System_UInt32
453 && args[4].ArgumentType == universe.System_UInt32)
455 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);
461 if ((this.Attributes & ParameterAttributes.Optional) != 0)
463 return Missing.Value;
469 public override CustomModifiers __GetCustomModifiers()
471 return position == -1
472 ? method.MethodSignature.GetReturnTypeCustomModifiers(method)
473 : method.MethodSignature.GetParameterCustomModifiers(method, position);
476 public override MemberInfo Member
480 // return the right ConstructorInfo wrapper
481 return method.Module.ResolveMethod(method.MetadataToken);
485 public override int MetadataToken
489 // for parameters that don't have a row in the Param table, we return 0x08000000 (because index is -1 in that case),
491 return (ParamTable.Index << 24) + index + 1;
495 internal override Module Module
497 get { return method.Module; }
500 internal override IList<CustomAttributeData> GetCustomAttributesData(Type attributeType)
502 IList<CustomAttributeData> list = base.GetCustomAttributesData(attributeType);
503 if ((this.Attributes & ParameterAttributes.HasFieldMarshal) != 0
504 && (attributeType == null || attributeType.IsAssignableFrom(this.Module.universe.System_Runtime_InteropServices_MarshalAsAttribute)))
506 list.Add(MarshalSpec.GetMarshalAsAttribute(this.Module, this.MetadataToken));