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 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 void __SetCallingConvention(CallingConventions callingConvention)
409 this.callingConvention = callingConvention;
412 public override MethodImplAttributes GetMethodImplementationFlags()
417 private sealed class ParameterInfoImpl : ParameterInfo
419 private readonly MethodBuilder method;
420 private readonly int parameter;
422 internal ParameterInfoImpl(MethodBuilder method, int parameter)
424 this.method = method;
425 this.parameter = parameter;
428 private ParameterBuilder ParameterBuilder
432 if (method.parameters != null)
434 foreach (ParameterBuilder pb in method.parameters)
436 if (pb.Position == parameter)
446 public override string Name
450 ParameterBuilder pb = this.ParameterBuilder;
451 return pb != null ? pb.Name : null;
455 public override Type ParameterType
457 get { return parameter == -1 ? method.returnType : method.parameterTypes[parameter]; }
460 public override ParameterAttributes Attributes
464 ParameterBuilder pb = this.ParameterBuilder;
465 return pb != null ? (ParameterAttributes)pb.Attributes : ParameterAttributes.None;
469 public override int Position
471 get { return parameter; }
474 public override object RawDefaultValue
478 ParameterBuilder pb = this.ParameterBuilder;
479 if (pb != null && (pb.Attributes & (int)ParameterAttributes.HasDefault) != 0)
481 return method.ModuleBuilder.Constant.GetRawConstantValue(method.ModuleBuilder, pb.PseudoToken);
483 if (pb != null && (pb.Attributes & (int)ParameterAttributes.Optional) != 0)
485 return Missing.Value;
491 private Type[] GetCustomModifiers(int optOrReq)
493 if (method.modifiers == null || method.modifiers[parameter + 1] == null)
495 return Type.EmptyTypes;
497 return Util.Copy(method.modifiers[parameter + 1][optOrReq]);
500 public override Type[] GetOptionalCustomModifiers()
502 return GetCustomModifiers(0);
505 public override Type[] GetRequiredCustomModifiers()
507 return GetCustomModifiers(1);
510 public override MemberInfo Member
512 get { return method; }
515 public override int MetadataToken
519 ParameterBuilder pb = this.ParameterBuilder;
520 return pb != null ? pb.PseudoToken : 0x08000000;
524 internal override Module Module
526 get { return method.Module; }
530 public override ParameterInfo[] GetParameters()
532 ParameterInfo[] parameters = new ParameterInfo[parameterTypes.Length];
533 for (int i = 0; i < parameters.Length; i++)
535 parameters[i] = new ParameterInfoImpl(this, i);
540 internal override int ParameterCount
542 get { return parameterTypes.Length; }
545 public override Type DeclaringType
547 get { return typeBuilder.IsModulePseudoType ? null : typeBuilder; }
550 public override string Name
555 public override CallingConventions CallingConvention
557 get { return callingConvention; }
560 public override int MetadataToken
562 get { return pseudoToken; }
565 public override bool IsGenericMethod
567 get { return gtpb != null; }
570 public override bool IsGenericMethodDefinition
572 get { return gtpb != null; }
575 public override Module Module
577 get { return typeBuilder.Module; }
580 public Module GetModule()
582 return typeBuilder.Module;
585 public MethodToken GetToken()
587 return new MethodToken(pseudoToken);
590 public override MethodBody GetMethodBody()
592 throw new NotSupportedException();
595 public bool InitLocals
597 get { return initLocals; }
598 set { initLocals = value; }
601 public void __AddUnmanagedExport(string name, int ordinal)
603 this.ModuleBuilder.AddUnmanagedExport(name, ordinal, this, new RelativeVirtualAddress(0xFFFFFFFF));
608 this.nameIndex = this.ModuleBuilder.Strings.Add(name);
609 this.signature = this.ModuleBuilder.GetSignatureBlobIndex(this.MethodSignature);
611 __ReleaseILGenerator();
613 if (declarativeSecurity != null)
615 this.ModuleBuilder.AddDeclarativeSecurity(pseudoToken, declarativeSecurity);
619 internal ModuleBuilder ModuleBuilder
621 get { return typeBuilder.ModuleBuilder; }
624 internal void WriteMethodDefRecord(int baseRVA, MetadataWriter mw, ref int paramList)
628 mw.Write(rva + baseRVA);
634 mw.Write((short)implFlags);
635 mw.Write((short)attributes);
636 mw.WriteStringIndex(nameIndex);
637 mw.WriteBlobIndex(signature);
638 mw.WriteParam(paramList);
639 if (parameters != null)
641 paramList += parameters.Count;
645 internal void WriteParamRecords(MetadataWriter mw)
647 if (parameters != null)
649 foreach (ParameterBuilder pb in parameters)
651 pb.WriteParamRecord(mw);
656 internal void FixupToken(int token, ref int parameterToken)
658 typeBuilder.ModuleBuilder.RegisterTokenFixup(this.pseudoToken, token);
659 if (parameters != null)
661 foreach (ParameterBuilder pb in parameters)
663 pb.FixupToken(parameterToken++);
668 internal override MethodSignature MethodSignature
672 if (methodSignature == null)
674 methodSignature = MethodSignature.MakeFromBuilder(returnType, parameterTypes, modifiers, callingConvention, gtpb == null ? 0 : gtpb.Length);
676 return methodSignature;
680 internal override int ImportTo(ModuleBuilder other)
682 if (typeBuilder.IsGenericTypeDefinition)
684 return other.ImportMember(TypeBuilder.GetMethod(typeBuilder, this));
686 else if (other == typeBuilder.ModuleBuilder)
692 return other.ImportMethodOrField(typeBuilder, name, this.MethodSignature);
696 internal void CheckBaked()
698 typeBuilder.CheckBaked();