25using System.Buffers.Binary;
26using System.Collections.Generic;
27using System.Diagnostics;
28using System.Diagnostics.SymbolStore;
30using System.Reflection.Metadata;
31using System.Reflection.Metadata.Ecma335;
33using System.Runtime.InteropServices;
41 internal sealed class MethodBuilder :
MethodInfo
44 readonly TypeBuilder type;
46 readonly
int pseudoToken;
50 Type[] parameterTypes = Array.Empty<
Type>();
52 MethodAttributes attributes;
53 MethodImplAttributes implFlags;
55 List<ParameterBuilder> parameters;
56 ILGenerator m_ilGenerator;
57 GenericTypeParameterBuilder[] gtpb;
58 List<CustomAttributeBuilder> declarativeSecurity;
60 CallingConventions callingConvention;
61 bool initLocals =
true;
63 StringHandle nameIndex;
69 byte[] m_localSignature;
70 ExceptionHandler[] m_exceptions;
71 int[] m_mdMethodFixups;
72 internal LocalSymInfo m_localSymInfo;
81 internal MethodBuilder(TypeBuilder typeBuilder,
string name, MethodAttributes attributes, CallingConventions callingConvention)
83 this.type = typeBuilder;
85 this.pseudoToken = typeBuilder.ModuleBuilder.AllocPseudoToken();
86 this.attributes = attributes;
87 if ((attributes & MethodAttributes.Static) == 0)
88 callingConvention |= CallingConventions.HasThis;
89 this.callingConvention = callingConvention;
90 this.returnType =
Module.Universe.System_Void;
93 public ILGenerator GetILGenerator()
95 return GetILGenerator(16);
98 public ILGenerator GetILGenerator(
int streamSize)
101 throw new InvalidOperationException();
103 return m_ilGenerator ??=
new ILGenerator(
this, streamSize);
106 public void SetCustomAttribute(
ConstructorInfo con,
byte[] binaryAttribute)
108 SetCustomAttribute(
new CustomAttributeBuilder(con, binaryAttribute));
111 private void SetDllImportPseudoCustomAttribute(CustomAttributeBuilder customBuilder)
113 var callingConvention = customBuilder.GetFieldValue<
CallingConvention>(
"CallingConvention");
114 var charSet = customBuilder.GetFieldValue<CharSet>(
"CharSet");
115 SetDllImportPseudoCustomAttribute((
string)customBuilder.GetConstructorArgument(0),
116 (
string)customBuilder.GetFieldValue(
"EntryPoint"),
119 (
bool?)customBuilder.GetFieldValue(
"BestFitMapping"),
120 (
bool?)customBuilder.GetFieldValue(
"ThrowOnUnmappableChar"),
121 (
bool?)customBuilder.GetFieldValue(
"SetLastError"),
122 (
bool?)customBuilder.GetFieldValue(
"PreserveSig"),
123 (
bool?)customBuilder.GetFieldValue(
"ExactSpelling"));
126 internal void SetDllImportPseudoCustomAttribute(
string dllName,
string entryName,
CallingConvention? nativeCallConv, CharSet? nativeCharSet,
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;
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;
148 if (bestFitMapping.HasValue)
149 flags |= bestFitMapping.Value ? BestFitOn : BestFitOff;
151 if (throwOnUnmappableChar.HasValue)
152 flags |= throwOnUnmappableChar.Value ? CharMapErrorOn : CharMapErrorOff;
154 if (nativeCallConv.HasValue)
156 flags &= ~CallConvMask;
157 switch (nativeCallConv.Value)
160 flags |= CallConvCdecl;
162 case System.
Runtime.InteropServices.CallingConvention.FastCall:
163 flags |= CallConvFastcall;
165 case System.
Runtime.InteropServices.CallingConvention.StdCall:
166 flags |= CallConvStdcall;
168 case System.
Runtime.InteropServices.CallingConvention.ThisCall:
169 flags |= CallConvThiscall;
171 case System.
Runtime.InteropServices.CallingConvention.Winapi:
172 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;
195 if (exactSpelling.HasValue && exactSpelling.Value)
198 if (!preserveSig.HasValue || preserveSig.Value)
199 implFlags |= MethodImplAttributes.PreserveSig;
201 if (setLastError.HasValue && setLastError.Value)
202 flags |= SupportsLastError;
205 rec.MappingFlags = flags;
206 rec.MemberForwarded = pseudoToken;
207 rec.ImportName = ModuleBuilder.GetOrAddString(entryName ?? name);
208 rec.ImportScope = MetadataTokens.GetToken(MetadataTokens.ModuleReferenceHandle(ModuleBuilder.ModuleRefTable.FindOrAddRecord(dllName ==
null ?
default : ModuleBuilder.GetOrAddString(dllName))));
209 ModuleBuilder.ImplMapTable.AddRecord(rec);
212 void SetMethodImplAttribute(CustomAttributeBuilder customBuilder)
214 MethodImplOptions opt;
215 switch (customBuilder.Constructor.ParameterCount)
222 var val = customBuilder.GetConstructorArgument(0);
224 opt = (MethodImplOptions)s;
226 opt = (MethodImplOptions)(
int)val;
228 opt = (MethodImplOptions)val;
232 throw new NotSupportedException();
234 implFlags = (MethodImplAttributes)opt;
235 var type = customBuilder.GetFieldValue<MethodCodeType>(
"MethodCodeType");
237 implFlags |= (MethodImplAttributes)type;
240 public void SetCustomAttribute(CustomAttributeBuilder customBuilder)
242 switch (customBuilder.KnownCA)
244 case KnownCA.DllImportAttribute:
245 SetDllImportPseudoCustomAttribute(customBuilder.DecodeBlob(
this.Module.Assembly));
246 attributes |= MethodAttributes.PinvokeImpl;
248 case KnownCA.MethodImplAttribute:
249 SetMethodImplAttribute(customBuilder.DecodeBlob(
this.Module.Assembly));
251 case KnownCA.PreserveSigAttribute:
252 implFlags |= MethodImplAttributes.PreserveSig;
254 case KnownCA.SpecialNameAttribute:
255 attributes |= MethodAttributes.SpecialName;
257 case KnownCA.SuppressUnmanagedCodeSecurityAttribute:
258 attributes |= MethodAttributes.HasSecurity;
261 ModuleBuilder.SetCustomAttribute(pseudoToken, customBuilder);
266 public void __AddDeclarativeSecurity(CustomAttributeBuilder customBuilder)
268 attributes |= MethodAttributes.HasSecurity;
269 declarativeSecurity ??=
new List<CustomAttributeBuilder>();
270 declarativeSecurity.Add(customBuilder);
273 public void AddDeclarativeSecurity(
System.Security.Permissions.SecurityAction securityAction,
System.Security.PermissionSet permissionSet)
275 this.ModuleBuilder.AddDeclarativeSecurity(pseudoToken, securityAction, permissionSet);
276 this.attributes |= MethodAttributes.HasSecurity;
279 public void SetImplementationFlags(MethodImplAttributes attributes)
281 implFlags = attributes;
284 public ParameterBuilder DefineParameter(
int position, ParameterAttributes attributes,
string strParamName)
286 parameters ??=
new List<ParameterBuilder>();
288 ModuleBuilder.ParamTable.AddVirtualRecord();
289 var pb =
new ParameterBuilder(
this, position, attributes, strParamName);
290 if (parameters.Count == 0 || position >= parameters[parameters.Count - 1].Position)
296 for (var i = 0; i < parameters.Count; i++)
298 if (parameters[i].Position > position)
300 parameters.Insert(i, pb);
311 if (methodSignature !=
null)
312 throw new InvalidOperationException(
"The method signature can not be modified after it has been used.");
315 public void SetParameters(params
Type[] parameterTypes)
318 this.parameterTypes =
Util.Copy(parameterTypes);
321 public void SetReturnType(
Type returnType)
324 this.returnType = returnType ?? this.
Module.Universe.System_Void;
327 public void SetSignature(
Type returnType,
Type[] returnTypeRequiredCustomModifiers,
Type[] returnTypeOptionalCustomModifiers,
Type[] parameterTypes,
Type[][] parameterTypeRequiredCustomModifiers,
Type[][] parameterTypeOptionalCustomModifiers)
329 SetSignature(returnType, parameterTypes,
PackedCustomModifiers.CreateFromExternal(returnTypeOptionalCustomModifiers, returnTypeRequiredCustomModifiers, parameterTypeOptionalCustomModifiers, parameterTypeRequiredCustomModifiers,
Util.NullSafeLength(parameterTypes)));
332 public void __SetSignature(
Type returnType, CustomModifiers returnTypeCustomModifiers,
Type[] parameterTypes, CustomModifiers[] parameterTypeCustomModifiers)
334 SetSignature(returnType, parameterTypes,
PackedCustomModifiers.CreateFromExternal(returnTypeCustomModifiers, parameterTypeCustomModifiers,
Util.NullSafeLength(parameterTypes)));
340 this.returnType = returnType ?? this.
Module.Universe.System_Void;
341 this.parameterTypes =
Util.Copy(parameterTypes);
342 this.customModifiers = customModifiers;
345 public GenericTypeParameterBuilder[] DefineGenericParameters(params
string[] names)
349 throw new InvalidOperationException(
"Generic parameters already defined.");
351 gtpb =
new GenericTypeParameterBuilder[names.Length];
352 for (
int i = 0; i < names.Length; i++)
353 gtpb[i] =
new GenericTypeParameterBuilder(names[i],
this, i);
355 return (GenericTypeParameterBuilder[])gtpb.Clone();
358 public override MethodInfo MakeGenericMethod(params
Type[] typeArguments)
363 public override MethodInfo GetGenericMethodDefinition()
366 throw new InvalidOperationException();
371 public override Type[] GetGenericArguments()
373 return Util.Copy(gtpb);
376 internal override Type GetGenericMethodArgument(
int index)
381 internal override int GetGenericMethodArgumentCount()
383 return gtpb ==
null ? 0 : gtpb.Length;
386 public override Type ReturnType
388 get {
return returnType; }
393 get {
return new ParameterInfoImpl(
this, -1); }
396 public override MethodAttributes Attributes
398 get {
return attributes; }
401 public void __SetAttributes(MethodAttributes attributes)
403 this.attributes = attributes;
406 public void __SetCallingConvention(CallingConventions callingConvention)
408 this.callingConvention = callingConvention;
409 this.methodSignature =
null;
412 public override MethodImplAttributes GetMethodImplementationFlags()
420 readonly MethodBuilder method;
421 readonly
int parameter;
428 internal ParameterInfoImpl(MethodBuilder method,
int parameter)
430 this.method = method;
431 this.parameter = parameter;
434 ParameterBuilder ParameterBuilder
438 if (method.parameters !=
null)
439 foreach (var pb
in method.parameters)
440 if (pb.Position - 1 == parameter)
447 public override string Name
451 var pb = ParameterBuilder;
452 return pb !=
null ? pb.Name :
null;
456 public override Type ParameterType
458 get {
return parameter == -1 ? method.returnType : method.parameterTypes[parameter]; }
461 public override ParameterAttributes Attributes
465 var pb = ParameterBuilder;
466 return pb !=
null ? (ParameterAttributes)pb.Attributes : ParameterAttributes.None;
470 public override int Position
472 get {
return parameter; }
475 public override object RawDefaultValue
479 var pb = ParameterBuilder;
480 if (pb !=
null && (pb.Attributes & (
int)ParameterAttributes.HasDefault) != 0)
481 return method.ModuleBuilder.ConstantTable.GetRawConstantValue(method.ModuleBuilder, pb.PseudoToken);
482 if (pb !=
null && (pb.Attributes & (
int)ParameterAttributes.Optional) != 0)
483 return Missing.Value;
489 public override CustomModifiers __GetCustomModifiers()
491 return method.customModifiers.GetParameterCustomModifiers(parameter);
494 public override bool __TryGetFieldMarshal(out FieldMarshal fieldMarshal)
496 fieldMarshal =
new FieldMarshal();
502 get {
return method; }
505 public override int MetadataToken
509 var pb = ParameterBuilder;
510 return pb !=
null ? pb.PseudoToken : 0x08000000;
516 get {
return method.Module; }
524 for (
int i = 0; i < parameters.Length; i++)
525 parameters[i] =
new ParameterInfoImpl(
this, i);
530 internal override Type[] GetParameterTypes()
532 return parameterTypes;
535 internal override int ParameterCount
537 get {
return parameterTypes.Length; }
540 public override Type DeclaringType
542 get {
return type.IsModulePseudoType ? null : type; }
545 public override string Name
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; }
572 get {
return type.Module; }
580 public MethodToken GetToken()
582 return new MethodToken(pseudoToken);
585 public override MethodBody GetMethodBody()
587 throw new NotSupportedException();
590 public override int __MethodRVA
592 get {
throw new NotImplementedException(); }
595 public bool InitLocals
597 get {
return initLocals; }
598 set { initLocals = value; }
601 public void CreateMethodBody(
byte[] il,
int count)
604 throw new NotSupportedException();
605 if (il.Length != count)
606 Array.Resize(
ref il, count);
608 SetMethodBody(il, 16,
null,
null,
null);
615 void ThrowIfShouldNotHaveBody()
617 if ((implFlags & MethodImplAttributes.CodeTypeMask) != MethodImplAttributes.IL ||
618 (implFlags & MethodImplAttributes.Unmanaged) != 0 ||
619 (attributes & MethodAttributes.PinvokeImpl) != 0 ||
621 throw new InvalidOperationException(
"Method body should not exist.");
632 public void SetMethodBody(
byte[] il,
int maxStack,
byte[] localSignature, IEnumerable<ExceptionHandler> exceptionHandlers, IEnumerable<int> tokenFixups)
635 throw new InvalidOperationException(
"Method already has a body.");
637 ThrowIfShouldNotHaveBody();
638 SetMethodBody(il, maxStack, localSignature, exceptionHandlers?.ToArray(), tokenFixups?.ToArray());
649 void SetMethodBody(
byte[] il,
int maxStack,
byte[] localSignature, ExceptionHandler[] exceptionHandlers,
int[] tokenFixups)
652 this.m_maxStack = maxStack;
653 this.m_localSignature = localSignature;
654 this.m_exceptions = exceptionHandlers;
655 this.m_mdMethodFixups = tokenFixups;
660 nameIndex = ModuleBuilder.GetOrAddString(name);
664 if (m_ilGenerator !=
null)
666 if (m_ilGenerator.m_ScopeTree.m_iOpenScopeCount != 0)
667 throw new InvalidOperationException(
"Local variable scope was not properly closed.");
670 SetMethodBody(m_ilGenerator.BakeByteArray(), m_ilGenerator.GetMaxStackSize(), m_ilGenerator.m_localSignature.GetSignature(), GetExceptions(m_ilGenerator.GetExceptions()), m_ilGenerator.GetTokenFixups());
673 if (declarativeSecurity !=
null)
674 ModuleBuilder.AddDeclarativeSecurity(pseudoToken, declarativeSecurity);
682 ExceptionHandler[] GetExceptions(__ExceptionInfo[] excp)
688 int numExceptions = CalculateNumberOfExceptions(excp);
689 if (numExceptions > 0)
692 var m_exceptions =
new ExceptionHandler[numExceptions];
694 for (
int i = 0; i < excp.Length; i++)
696 var numCatch = excp[i].GetNumberOfCatches();
697 var start = excp[i].GetStartAddress();
698 var end = excp[i].GetEndAddress();
699 var type = excp[i].GetExceptionTypes();
701 var filterAddrs = excp[i].GetFilterAddresses();
702 var catchAddrs = excp[i].GetCatchAddresses();
703 var catchEndAddrs = excp[i].GetCatchEndAddresses();
704 var catchClass = excp[i].GetCatchClass();
707 for (
int j = 0; j < numCatch; j++)
709 int tkExceptionClass = 0;
710 if (catchClass[j] !=
null)
712 tkExceptionClass = ModuleBuilder.GetTypeTokenForMemberRef(catchClass[j]);
713 Debug.Assert(ModuleBuilder.IsPseudoToken(tkExceptionClass) ==
false);
718 case __ExceptionInfo.None:
719 case __ExceptionInfo.Fault:
720 case __ExceptionInfo.Filter:
721 m_exceptions[counter++] =
new ExceptionHandler(start, end, filterAddrs[j], catchAddrs[j], catchEndAddrs[j], type[j], tkExceptionClass);
724 case __ExceptionInfo.Finally:
725 m_exceptions[counter++] =
new ExceptionHandler(start, excp[i].GetFinallyEndAddress(), filterAddrs[j], catchAddrs[j], catchEndAddrs[j], type[j], tkExceptionClass);
734 return Array.Empty<ExceptionHandler>();
745 static int CalculateNumberOfExceptions(__ExceptionInfo[] excp)
750 for (
int i = 0; i < excp.Length; i++)
751 num += excp[i].GetNumberOfCatches();
756 internal ModuleBuilder ModuleBuilder => type.ModuleBuilder;
763 internal void WriteMetadata(
ref int paramList)
765 Debug.Assert(IsBaked);
768 var localSignatureHandle =
default(StandaloneSignatureHandle);
769 if (m_localSignature !=
null)
771 var buf =
new BlobBuilder();
772 buf.WriteBytes(m_localSignature);
773 localSignatureHandle = MetadataTokens.StandaloneSignatureHandle(ModuleBuilder.StandAloneSigTable.FindOrAddRecord(ModuleBuilder.GetOrAddBlob(buf)));
777 WriteBody(localSignatureHandle);
780 var t = (MethodDefinitionHandle)MetadataTokens.EntityHandle(ModuleBuilder.ResolvePseudoToken(pseudoToken));
783 var h = ModuleBuilder.Metadata.AddMethodDefinition(
784 (
System.Reflection.MethodAttributes)attributes,
785 (
System.Reflection.MethodImplAttributes)implFlags,
789 MetadataTokens.ParameterHandle(paramList));
790 Debug.Assert(h == t);
793 WriteSymbols(h, localSignatureHandle);
795 if (parameters !=
null)
796 paramList += parameters.Count;
799 m_ilGenerator =
null;
802 m_localSymInfo =
null;
809 void WriteBody(StandaloneSignatureHandle localSignatureHandle)
812 if (m_ubBody ==
null)
816 var hasSmallExceptions = HasSmallExceptionRegions(m_exceptions);
817 var methodBody = ModuleBuilder.MethodBodyEncoder.AddMethodBody(m_ubBody.Length, m_maxStack, m_exceptions !=
null ? m_exceptions.Length : 0, hasSmallExceptions, localSignatureHandle, initLocals ? MethodBodyAttributes.InitLocals : MethodBodyAttributes.None,
false);
818 var ilBytes = methodBody.Instructions.GetBytes();
821 if (m_mdMethodFixups !=
null && m_mdMethodFixups.Length > 0)
823 var span = m_ubBody.AsSpan();
824 foreach (
int offset
in m_mdMethodFixups)
826 var ilp = span.Slice(offset,
sizeof(
int));
827 BinaryPrimitives.WriteInt32LittleEndian(ilp, ModuleBuilder.ResolvePseudoToken(BinaryPrimitives.ReadInt32LittleEndian(ilp)));
832 m_ubBody.CopyTo(ilBytes.AsSpan());
835 if (m_exceptions !=
null)
836 foreach (var e
in m_exceptions)
837 methodBody.ExceptionRegions.Add((ExceptionRegionKind)(
int)e.Kind, e.TryOffset, e.TryLength, e.HandlerOffset, e.HandlerLength, MetadataTokens.EntityHandle(e.ExceptionTypeToken), e.FilterOffset);
840 rva = methodBody.Offset;
848 bool HasSmallExceptionRegions(ExceptionHandler[] exceptions)
850 if (exceptions ==
null)
853 if (ExceptionRegionEncoder.IsSmallRegionCount(exceptions.Length) ==
false)
856 foreach (var e
in exceptions)
857 if (ExceptionRegionEncoder.IsSmallExceptionRegion(e.TryOffset, e.TryLength) ==
false || ExceptionRegionEncoder.IsSmallExceptionRegion(e.HandlerOffset, e.HandlerLength) ==
false)
868 void WriteSymbols(MethodDefinitionHandle methodHandle, StandaloneSignatureHandle localSignatureHandle)
870 if (ModuleBuilder.GetSymWriter() !=
null)
875 SymbolToken tk =
new SymbolToken(MetadataTokens.GetToken(methodHandle));
876 ISymbolWriter symWriter = ModuleBuilder.GetSymWriter();
879 if (symWriter is IMetadataSymbolWriter metadataSymWriter)
880 metadataSymWriter.OpenMethod(tk, localSignatureHandle);
882 symWriter.OpenMethod(tk);
885 if (m_ilGenerator !=
null)
889 symWriter.OpenScope(0);
892 m_localSymInfo?.EmitLocalSymInfo(symWriter);
893 m_ilGenerator.m_ScopeTree.EmitScopeTree(symWriter);
894 m_ilGenerator.m_LineNumberInfo.EmitLineNumberInfo(symWriter);
896 symWriter.CloseScope(m_ilGenerator.ILOffset);
900 symWriter.CloseMethod();
904 internal void WriteParamRecords()
906 if (parameters !=
null)
907 foreach (var pb
in parameters)
911 internal void FixupToken(
int token,
ref int parameterToken)
913 type.ModuleBuilder.RegisterTokenFixup(pseudoToken, token);
914 if (parameters !=
null)
915 foreach (var pb
in parameters)
916 pb.FixupToken(parameterToken++);
919 internal override MethodSignature MethodSignature => methodSignature ??=
MethodSignature.MakeFromBuilder(returnType ?? type.Universe.System_Void, parameterTypes ??
Type.EmptyTypes, customModifiers, callingConvention, gtpb ==
null ? 0 : gtpb.Length);
921 internal override int ImportTo(ModuleBuilder other)
923 return other.ImportMethodOrField(type, name, this.MethodSignature);
926 internal void CheckBaked()
931 internal override int GetCurrentToken()
933 if (type.ModuleBuilder.IsSaved)
934 return type.ModuleBuilder.ResolvePseudoToken(pseudoToken);
939 internal bool IsTypeCreated()
941 return type.IsCreated();
944 internal override bool IsBaked => type.IsBaked;
IKVM.Reflection.Module Module
IKVM.Reflection.Type Type
IKVM.Reflection.ConstructorInfo ConstructorInfo
IKVM.Reflection.MemberInfo MemberInfo
IKVM.Reflection.MethodInfo MethodInfo
IKVM.Reflection.ParameterInfo ParameterInfo
global::java.lang.invoke.LambdaForm.Name Name
System.Runtime.InteropServices.CallingConvention CallingConvention
Represents a method signature from IL metadadata.
KnownCA
These are the pseudo-custom attributes that are recognized by name by the runtime (i....