2 Copyright (C) 2008-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.
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 PackedCustomModifiers customModifiers;
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), this);
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 if (parameters == null)
306 parameters = new List<ParameterBuilder>();
308 this.ModuleBuilder.Param.AddVirtualRecord();
309 ParameterBuilder pb = new ParameterBuilder(this.ModuleBuilder, position, attributes, strParamName);
310 if (parameters.Count == 0 || position > parameters[parameters.Count - 1].Position)
316 for (int i = 0; i < parameters.Count; i++)
318 if (parameters[i].Position > position)
320 parameters.Insert(i, pb);
328 private void CheckSig()
330 if (methodSignature != null)
332 throw new InvalidOperationException("The method signature can not be modified after it has been used.");
336 public void SetParameters(params Type[] parameterTypes)
339 this.parameterTypes = Util.Copy(parameterTypes);
342 public void SetReturnType(Type returnType)
345 this.returnType = returnType ?? this.Module.universe.System_Void;
348 public void SetSignature(Type returnType, Type[] returnTypeRequiredCustomModifiers, Type[] returnTypeOptionalCustomModifiers, Type[] parameterTypes, Type[][] parameterTypeRequiredCustomModifiers, Type[][] parameterTypeOptionalCustomModifiers)
350 SetSignature(returnType, parameterTypes, PackedCustomModifiers.CreateFromExternal(returnTypeOptionalCustomModifiers, returnTypeRequiredCustomModifiers,
351 parameterTypeOptionalCustomModifiers, parameterTypeRequiredCustomModifiers, Util.NullSafeLength(parameterTypes)));
354 public void __SetSignature(Type returnType, CustomModifiers returnTypeCustomModifiers, Type[] parameterTypes, CustomModifiers[] parameterTypeCustomModifiers)
356 SetSignature(returnType, parameterTypes, PackedCustomModifiers.CreateFromExternal(returnTypeCustomModifiers, parameterTypeCustomModifiers, Util.NullSafeLength(parameterTypes)));
359 private void SetSignature(Type returnType, Type[] parameterTypes, PackedCustomModifiers customModifiers)
362 this.returnType = returnType ?? this.Module.universe.System_Void;
363 this.parameterTypes = Util.Copy(parameterTypes);
364 this.customModifiers = customModifiers;
367 public GenericTypeParameterBuilder[] DefineGenericParameters(params string[] names)
370 gtpb = new GenericTypeParameterBuilder[names.Length];
371 for (int i = 0; i < names.Length; i++)
373 gtpb[i] = new GenericTypeParameterBuilder(names[i], null, this, i);
375 return (GenericTypeParameterBuilder[])gtpb.Clone();
378 public override MethodInfo MakeGenericMethod(params Type[] typeArguments)
380 return new GenericMethodInstance(typeBuilder, this, typeArguments);
383 public override MethodInfo GetGenericMethodDefinition()
387 throw new InvalidOperationException();
392 public override Type[] GetGenericArguments()
394 return Util.Copy(gtpb);
397 internal override Type GetGenericMethodArgument(int index)
402 internal override int GetGenericMethodArgumentCount()
404 return gtpb == null ? 0 : gtpb.Length;
407 public override Type ReturnType
409 get { return returnType; }
412 public override ParameterInfo ReturnParameter
414 get { return new ParameterInfoImpl(this, -1); }
417 public override MethodAttributes Attributes
419 get { return attributes; }
422 public void __SetAttributes(MethodAttributes attributes)
424 this.attributes = attributes;
427 public void __SetCallingConvention(CallingConventions callingConvention)
429 this.callingConvention = callingConvention;
430 this.methodSignature = null;
433 public override MethodImplAttributes GetMethodImplementationFlags()
438 private sealed class ParameterInfoImpl : ParameterInfo
440 private readonly MethodBuilder method;
441 private readonly int parameter;
443 internal ParameterInfoImpl(MethodBuilder method, int parameter)
445 this.method = method;
446 this.parameter = parameter;
449 private ParameterBuilder ParameterBuilder
453 if (method.parameters != null)
455 foreach (ParameterBuilder pb in method.parameters)
457 // ParameterBuilder.Position is 1-based
458 if (pb.Position - 1 == parameter)
468 public override string Name
472 ParameterBuilder pb = this.ParameterBuilder;
473 return pb != null ? pb.Name : null;
477 public override Type ParameterType
479 get { return parameter == -1 ? method.returnType : method.parameterTypes[parameter]; }
482 public override ParameterAttributes Attributes
486 ParameterBuilder pb = this.ParameterBuilder;
487 return pb != null ? (ParameterAttributes)pb.Attributes : ParameterAttributes.None;
491 public override int Position
493 get { return parameter; }
496 public override object RawDefaultValue
500 ParameterBuilder pb = this.ParameterBuilder;
501 if (pb != null && (pb.Attributes & (int)ParameterAttributes.HasDefault) != 0)
503 return method.ModuleBuilder.Constant.GetRawConstantValue(method.ModuleBuilder, pb.PseudoToken);
505 if (pb != null && (pb.Attributes & (int)ParameterAttributes.Optional) != 0)
507 return Missing.Value;
513 public override CustomModifiers __GetCustomModifiers()
515 return method.customModifiers.GetParameterCustomModifiers(parameter);
518 public override bool __TryGetFieldMarshal(out FieldMarshal fieldMarshal)
520 fieldMarshal = new FieldMarshal();
524 public override MemberInfo Member
526 get { return method; }
529 public override int MetadataToken
533 ParameterBuilder pb = this.ParameterBuilder;
534 return pb != null ? pb.PseudoToken : 0x08000000;
538 internal override Module Module
540 get { return method.Module; }
544 public override ParameterInfo[] GetParameters()
546 ParameterInfo[] parameters = new ParameterInfo[parameterTypes.Length];
547 for (int i = 0; i < parameters.Length; i++)
549 parameters[i] = new ParameterInfoImpl(this, i);
554 internal override int ParameterCount
556 get { return parameterTypes.Length; }
559 public override Type DeclaringType
561 get { return typeBuilder.IsModulePseudoType ? null : typeBuilder; }
564 public override string Name
569 public override CallingConventions CallingConvention
571 get { return callingConvention; }
574 public override int MetadataToken
576 get { return pseudoToken; }
579 public override bool IsGenericMethod
581 get { return gtpb != null; }
584 public override bool IsGenericMethodDefinition
586 get { return gtpb != null; }
589 public override Module Module
591 get { return typeBuilder.Module; }
594 public Module GetModule()
596 return typeBuilder.Module;
599 public MethodToken GetToken()
601 return new MethodToken(pseudoToken);
604 public override MethodBody GetMethodBody()
606 throw new NotSupportedException();
609 public override int __MethodRVA
611 get { throw new NotImplementedException(); }
614 public bool InitLocals
616 get { return initLocals; }
617 set { initLocals = value; }
620 public void __AddUnmanagedExport(string name, int ordinal)
622 this.ModuleBuilder.AddUnmanagedExport(name, ordinal, this, new RelativeVirtualAddress(0xFFFFFFFF));
627 this.nameIndex = this.ModuleBuilder.Strings.Add(name);
628 this.signature = this.ModuleBuilder.GetSignatureBlobIndex(this.MethodSignature);
630 __ReleaseILGenerator();
632 if (declarativeSecurity != null)
634 this.ModuleBuilder.AddDeclarativeSecurity(pseudoToken, declarativeSecurity);
638 internal ModuleBuilder ModuleBuilder
640 get { return typeBuilder.ModuleBuilder; }
643 internal void WriteMethodDefRecord(int baseRVA, MetadataWriter mw, ref int paramList)
647 mw.Write(rva + baseRVA);
653 mw.Write((short)implFlags);
654 mw.Write((short)attributes);
655 mw.WriteStringIndex(nameIndex);
656 mw.WriteBlobIndex(signature);
657 mw.WriteParam(paramList);
658 if (parameters != null)
660 paramList += parameters.Count;
664 internal void WriteParamRecords(MetadataWriter mw)
666 if (parameters != null)
668 foreach (ParameterBuilder pb in parameters)
670 pb.WriteParamRecord(mw);
675 internal void FixupToken(int token, ref int parameterToken)
677 typeBuilder.ModuleBuilder.RegisterTokenFixup(this.pseudoToken, token);
678 if (parameters != null)
680 foreach (ParameterBuilder pb in parameters)
682 pb.FixupToken(parameterToken++);
687 internal override MethodSignature MethodSignature
691 if (methodSignature == null)
693 methodSignature = MethodSignature.MakeFromBuilder(returnType, parameterTypes, customModifiers, callingConvention, gtpb == null ? 0 : gtpb.Length);
695 return methodSignature;
699 internal override int ImportTo(ModuleBuilder other)
701 return other.ImportMethodOrField(typeBuilder, name, this.MethodSignature);
704 internal void CheckBaked()
706 typeBuilder.CheckBaked();
709 internal override int GetCurrentToken()
711 if (typeBuilder.ModuleBuilder.IsSaved)
713 return typeBuilder.ModuleBuilder.ResolvePseudoToken(pseudoToken);
721 internal override bool IsBaked
723 get { return typeBuilder.IsBaked; }