2 Copyright (C) 2008-2011 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.
26 using System.Diagnostics;
27 using System.Collections.Generic;
28 using System.Runtime.InteropServices;
29 using System.Runtime.CompilerServices;
30 using System.Diagnostics.SymbolStore;
31 using IKVM.Reflection.Metadata;
32 using IKVM.Reflection.Writer;
34 namespace IKVM.Reflection.Emit
36 public sealed class MethodBuilder : MethodInfo
38 private readonly TypeBuilder typeBuilder;
39 private readonly string name;
40 private readonly int pseudoToken;
41 private int nameIndex;
42 private int signature;
43 private Type returnType;
44 private Type[] parameterTypes;
45 private Type[][][] modifiers; // see PackedCustomModifiers
46 private MethodAttributes attributes;
47 private MethodImplAttributes implFlags;
48 private ILGenerator ilgen;
50 private readonly CallingConventions callingConvention;
51 private List<ParameterBuilder> parameters;
52 private GenericTypeParameterBuilder[] gtpb;
53 private List<CustomAttributeBuilder> declarativeSecurity;
54 private MethodSignature methodSignature;
55 private bool initLocals = true;
57 internal MethodBuilder(TypeBuilder typeBuilder, string name, MethodAttributes attributes, CallingConventions callingConvention)
59 this.typeBuilder = typeBuilder;
61 this.pseudoToken = typeBuilder.ModuleBuilder.AllocPseudoToken();
62 this.attributes = attributes;
63 if ((attributes & MethodAttributes.Static) == 0)
65 callingConvention |= CallingConventions.HasThis;
67 this.callingConvention = callingConvention;
70 public ILGenerator GetILGenerator()
72 return GetILGenerator(16);
75 public ILGenerator GetILGenerator(int streamSize)
79 throw new InvalidOperationException();
83 ilgen = new ILGenerator(typeBuilder.ModuleBuilder, streamSize);
88 public void __ReleaseILGenerator()
92 if (this.ModuleBuilder.symbolWriter != null)
94 this.ModuleBuilder.symbolWriter.OpenMethod(new SymbolToken(-pseudoToken | 0x06000000));
96 rva = ilgen.WriteBody(initLocals);
97 if (this.ModuleBuilder.symbolWriter != null)
99 this.ModuleBuilder.symbolWriter.CloseMethod();
105 public void SetCustomAttribute(ConstructorInfo con, byte[] binaryAttribute)
107 SetCustomAttribute(new CustomAttributeBuilder(con, binaryAttribute));
110 private void SetDllImportPseudoCustomAttribute(CustomAttributeBuilder customBuilder)
112 CallingConvention? callingConvention = customBuilder.GetFieldValue<CallingConvention>("CallingConvention");
113 CharSet? charSet = customBuilder.GetFieldValue<CharSet>("CharSet");
114 SetDllImportPseudoCustomAttribute((string)customBuilder.GetConstructorArgument(0),
115 (string)customBuilder.GetFieldValue("EntryPoint"),
118 (bool?)customBuilder.GetFieldValue("BestFitMapping"),
119 (bool?)customBuilder.GetFieldValue("ThrowOnUnmappableChar"),
120 (bool?)customBuilder.GetFieldValue("SetLastError"),
121 (bool?)customBuilder.GetFieldValue("PreserveSig"),
122 (bool?)customBuilder.GetFieldValue("ExactSpelling"));
125 internal void SetDllImportPseudoCustomAttribute(string dllName, string entryName, CallingConvention? nativeCallConv, CharSet? nativeCharSet,
126 bool? bestFitMapping, bool? throwOnUnmappableChar, bool? setLastError, bool? preserveSig, bool? exactSpelling)
128 const short NoMangle = 0x0001;
129 const short CharSetMask = 0x0006;
130 const short CharSetNotSpec = 0x0000;
131 const short CharSetAnsi = 0x0002;
132 const short CharSetUnicode = 0x0004;
133 const short CharSetAuto = 0x0006;
134 const short SupportsLastError = 0x0040;
135 const short CallConvMask = 0x0700;
136 const short CallConvWinapi = 0x0100;
137 const short CallConvCdecl = 0x0200;
138 const short CallConvStdcall = 0x0300;
139 const short CallConvThiscall = 0x0400;
140 const short CallConvFastcall = 0x0500;
141 // non-standard flags
142 const short BestFitOn = 0x0010;
143 const short BestFitOff = 0x0020;
144 const short CharMapErrorOn = 0x1000;
145 const short CharMapErrorOff = 0x2000;
146 short flags = CharSetNotSpec | CallConvWinapi;
147 if (bestFitMapping.HasValue)
149 flags |= bestFitMapping.Value ? BestFitOn : BestFitOff;
151 if (throwOnUnmappableChar.HasValue)
153 flags |= throwOnUnmappableChar.Value ? CharMapErrorOn : CharMapErrorOff;
155 if (nativeCallConv.HasValue)
157 flags &= ~CallConvMask;
158 switch (nativeCallConv.Value)
160 case System.Runtime.InteropServices.CallingConvention.Cdecl:
161 flags |= CallConvCdecl;
163 case System.Runtime.InteropServices.CallingConvention.FastCall:
164 flags |= CallConvFastcall;
166 case System.Runtime.InteropServices.CallingConvention.StdCall:
167 flags |= CallConvStdcall;
169 case System.Runtime.InteropServices.CallingConvention.ThisCall:
170 flags |= CallConvThiscall;
172 case System.Runtime.InteropServices.CallingConvention.Winapi:
173 flags |= CallConvWinapi;
177 if (nativeCharSet.HasValue)
179 flags &= ~CharSetMask;
180 switch (nativeCharSet.Value)
184 flags |= CharSetAnsi;
187 flags |= CharSetAuto;
189 case CharSet.Unicode:
190 flags |= CharSetUnicode;
194 if (exactSpelling.HasValue && exactSpelling.Value)
198 if (!preserveSig.HasValue || preserveSig.Value)
200 implFlags |= MethodImplAttributes.PreserveSig;
202 if (setLastError.HasValue && setLastError.Value)
204 flags |= SupportsLastError;
206 ImplMapTable.Record rec = new ImplMapTable.Record();
207 rec.MappingFlags = flags;
208 rec.MemberForwarded = pseudoToken;
209 rec.ImportName = this.ModuleBuilder.Strings.Add(entryName ?? name);
210 rec.ImportScope = this.ModuleBuilder.ModuleRef.FindOrAddRecord(dllName == null ? 0 : this.ModuleBuilder.Strings.Add(dllName));
211 this.ModuleBuilder.ImplMap.AddRecord(rec);
214 private void SetMethodImplAttribute(CustomAttributeBuilder customBuilder)
216 MethodImplOptions opt;
217 switch (customBuilder.Constructor.ParameterCount)
224 object val = customBuilder.GetConstructorArgument(0);
227 opt = (MethodImplOptions)(short)val;
231 opt = (MethodImplOptions)(int)val;
235 opt = (MethodImplOptions)val;
240 throw new NotSupportedException();
242 MethodCodeType? type = customBuilder.GetFieldValue<MethodCodeType>("MethodCodeType");
243 implFlags = (MethodImplAttributes)opt;
246 implFlags |= (MethodImplAttributes)type;
250 public void SetCustomAttribute(CustomAttributeBuilder customBuilder)
252 Universe u = this.ModuleBuilder.universe;
253 Type type = customBuilder.Constructor.DeclaringType;
254 if (type == u.System_Runtime_InteropServices_DllImportAttribute)
256 attributes |= MethodAttributes.PinvokeImpl;
257 SetDllImportPseudoCustomAttribute(customBuilder.DecodeBlob(this.Module.Assembly));
259 else if (type == u.System_Runtime_CompilerServices_MethodImplAttribute)
261 SetMethodImplAttribute(customBuilder.DecodeBlob(this.Module.Assembly));
263 else if (type == u.System_Runtime_InteropServices_PreserveSigAttribute)
265 implFlags |= MethodImplAttributes.PreserveSig;
267 else if (type == u.System_Runtime_CompilerServices_SpecialNameAttribute)
269 attributes |= MethodAttributes.SpecialName;
273 if (type == u.System_Security_SuppressUnmanagedCodeSecurityAttribute)
275 attributes |= MethodAttributes.HasSecurity;
277 this.ModuleBuilder.SetCustomAttribute(pseudoToken, customBuilder);
281 public void __AddDeclarativeSecurity(CustomAttributeBuilder customBuilder)
283 attributes |= MethodAttributes.HasSecurity;
284 if (declarativeSecurity == null)
286 declarativeSecurity = new List<CustomAttributeBuilder>();
288 declarativeSecurity.Add(customBuilder);
291 public void AddDeclarativeSecurity(System.Security.Permissions.SecurityAction securityAction, System.Security.PermissionSet permissionSet)
293 this.ModuleBuilder.AddDeclarativeSecurity(pseudoToken, securityAction, permissionSet);
294 this.attributes |= MethodAttributes.HasSecurity;
297 public void SetImplementationFlags(MethodImplAttributes attributes)
299 implFlags = attributes;
302 public ParameterBuilder DefineParameter(int position, ParameterAttributes attributes, string strParamName)
304 // the parameter is named "position", but it is actually a sequence number (i.e. 0 = return parameter, 1 = first parameter)
305 int sequence = position--;
306 if (parameters == null)
308 parameters = new List<ParameterBuilder>();
310 this.ModuleBuilder.Param.AddVirtualRecord();
311 ParameterBuilder pb = new ParameterBuilder(this.ModuleBuilder, sequence, attributes, strParamName);
312 if (parameters.Count == 0 || position > parameters[parameters.Count - 1].Position)
318 for (int i = 0; i < parameters.Count; i++)
320 if (parameters[i].Position > position)
322 parameters.Insert(i, pb);
330 public void SetParameters(params Type[] parameterTypes)
332 this.parameterTypes = Util.Copy(parameterTypes);
335 public void SetReturnType(Type returnType)
337 this.returnType = returnType ?? this.Module.universe.System_Void;
340 public void SetSignature(Type returnType, Type[] returnTypeRequiredCustomModifiers, Type[] returnTypeOptionalCustomModifiers, Type[] parameterTypes, Type[][] parameterTypeRequiredCustomModifiers, Type[][] parameterTypeOptionalCustomModifiers)
342 this.returnType = returnType ?? this.Module.universe.System_Void;
343 this.parameterTypes = Util.Copy(parameterTypes);
344 this.modifiers = PackedCustomModifiers.CreateFromExternal(returnTypeOptionalCustomModifiers, returnTypeRequiredCustomModifiers,
345 parameterTypeOptionalCustomModifiers, parameterTypeRequiredCustomModifiers, this.parameterTypes.Length);
348 public GenericTypeParameterBuilder[] DefineGenericParameters(params string[] names)
350 gtpb = new GenericTypeParameterBuilder[names.Length];
351 for (int i = 0; i < names.Length; i++)
353 gtpb[i] = new GenericTypeParameterBuilder(names[i], null, this, i);
355 return (GenericTypeParameterBuilder[])gtpb.Clone();
358 public override MethodInfo MakeGenericMethod(params Type[] typeArguments)
360 return new GenericMethodInstance(typeBuilder, this, typeArguments);
363 public override MethodInfo GetGenericMethodDefinition()
367 throw new InvalidOperationException();
372 public override Type[] GetGenericArguments()
374 return Util.Copy(gtpb);
377 internal override Type GetGenericMethodArgument(int index)
382 internal override int GetGenericMethodArgumentCount()
384 return gtpb == null ? 0 : gtpb.Length;
387 public override Type ReturnType
389 get { return returnType; }
392 public override ParameterInfo ReturnParameter
394 get { return new ParameterInfoImpl(this, -1); }
397 public override MethodAttributes Attributes
399 get { return attributes; }
402 public void __SetAttributes(MethodAttributes attributes)
404 this.attributes = attributes;
407 public override MethodImplAttributes GetMethodImplementationFlags()
412 private sealed class ParameterInfoImpl : ParameterInfo
414 private readonly MethodBuilder method;
415 private readonly int parameter;
417 internal ParameterInfoImpl(MethodBuilder method, int parameter)
419 this.method = method;
420 this.parameter = parameter;
423 private ParameterBuilder ParameterBuilder
427 if (method.parameters != null)
429 foreach (ParameterBuilder pb in method.parameters)
431 if (pb.Position == parameter)
441 public override string Name
445 ParameterBuilder pb = this.ParameterBuilder;
446 return pb != null ? pb.Name : null;
450 public override Type ParameterType
452 get { return parameter == -1 ? method.returnType : method.parameterTypes[parameter]; }
455 public override ParameterAttributes Attributes
459 ParameterBuilder pb = this.ParameterBuilder;
460 return pb != null ? (ParameterAttributes)pb.Attributes : ParameterAttributes.None;
464 public override int Position
466 get { return parameter; }
469 public override object RawDefaultValue
473 ParameterBuilder pb = this.ParameterBuilder;
474 if (pb != null && (pb.Attributes & (int)ParameterAttributes.HasDefault) != 0)
476 return method.ModuleBuilder.Constant.GetRawConstantValue(method.ModuleBuilder, pb.PseudoToken);
478 if (pb != null && (pb.Attributes & (int)ParameterAttributes.Optional) != 0)
480 return Missing.Value;
486 private Type[] GetCustomModifiers(int optOrReq)
488 if (method.modifiers == null || method.modifiers[parameter + 1] == null)
490 return Type.EmptyTypes;
492 return Util.Copy(method.modifiers[parameter + 1][optOrReq]);
495 public override Type[] GetOptionalCustomModifiers()
497 return GetCustomModifiers(0);
500 public override Type[] GetRequiredCustomModifiers()
502 return GetCustomModifiers(1);
505 public override MemberInfo Member
507 get { return method; }
510 public override int MetadataToken
514 ParameterBuilder pb = this.ParameterBuilder;
515 return pb != null ? pb.PseudoToken : 0x08000000;
519 internal override Module Module
521 get { return method.Module; }
525 public override ParameterInfo[] GetParameters()
527 ParameterInfo[] parameters = new ParameterInfo[parameterTypes.Length];
528 for (int i = 0; i < parameters.Length; i++)
530 parameters[i] = new ParameterInfoImpl(this, i);
535 internal override int ParameterCount
537 get { return parameterTypes.Length; }
540 public override Type DeclaringType
542 get { return typeBuilder.IsModulePseudoType ? null : typeBuilder; }
545 public override string Name
550 public override CallingConventions CallingConvention
552 get { return callingConvention; }
555 public override int MetadataToken
557 get { return pseudoToken; }
560 public override bool IsGenericMethod
562 get { return gtpb != null; }
565 public override bool IsGenericMethodDefinition
567 get { return gtpb != null; }
570 public override Module Module
572 get { return typeBuilder.Module; }
575 public Module GetModule()
577 return typeBuilder.Module;
580 public MethodToken GetToken()
582 return new MethodToken(pseudoToken);
585 public override MethodBody GetMethodBody()
587 throw new NotSupportedException();
590 public bool InitLocals
592 get { return initLocals; }
593 set { initLocals = value; }
598 this.nameIndex = this.ModuleBuilder.Strings.Add(name);
599 this.signature = this.ModuleBuilder.GetSignatureBlobIndex(this.MethodSignature);
601 __ReleaseILGenerator();
603 if (declarativeSecurity != null)
605 this.ModuleBuilder.AddDeclarativeSecurity(pseudoToken, declarativeSecurity);
609 internal ModuleBuilder ModuleBuilder
611 get { return typeBuilder.ModuleBuilder; }
614 internal void WriteMethodDefRecord(int baseRVA, MetadataWriter mw, ref int paramList)
618 mw.Write(rva + baseRVA);
624 mw.Write((short)implFlags);
625 mw.Write((short)attributes);
626 mw.WriteStringIndex(nameIndex);
627 mw.WriteBlobIndex(signature);
628 mw.WriteParam(paramList);
629 if (parameters != null)
631 paramList += parameters.Count;
635 internal void WriteParamRecords(MetadataWriter mw)
637 if (parameters != null)
639 foreach (ParameterBuilder pb in parameters)
641 pb.WriteParamRecord(mw);
646 internal void FixupToken(int token, ref int parameterToken)
648 typeBuilder.ModuleBuilder.RegisterTokenFixup(this.pseudoToken, token);
649 if (parameters != null)
651 foreach (ParameterBuilder pb in parameters)
653 pb.FixupToken(parameterToken++);
658 internal override MethodSignature MethodSignature
662 if (methodSignature == null)
664 methodSignature = MethodSignature.MakeFromBuilder(returnType, parameterTypes, modifiers, callingConvention, gtpb == null ? 0 : gtpb.Length);
666 return methodSignature;
670 internal override int ImportTo(ModuleBuilder other)
672 if (typeBuilder.IsGenericTypeDefinition)
674 return other.ImportMember(TypeBuilder.GetMethod(typeBuilder, this));
676 else if (other == typeBuilder.ModuleBuilder)
682 return other.ImportMethodOrField(typeBuilder, name, this.MethodSignature);
686 internal void CheckBaked()
688 typeBuilder.CheckBaked();