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)
372
throw new InvalidOperationException("Generic parameters already defined.");
374
gtpb = new GenericTypeParameterBuilder[names.Length];
375
for (int i = 0; i < names.Length; i++)
377
gtpb[i] = new GenericTypeParameterBuilder(names[i], null, this, i);
379
return (GenericTypeParameterBuilder[])gtpb.Clone();
382
public override MethodInfo MakeGenericMethod(params Type[] typeArguments)
384
return new GenericMethodInstance(typeBuilder, this, typeArguments);
387
public override MethodInfo GetGenericMethodDefinition()
391
throw new InvalidOperationException();
396
public override Type[] GetGenericArguments()
398
return Util.Copy(gtpb);
401
internal override Type GetGenericMethodArgument(int index)
406
internal override int GetGenericMethodArgumentCount()
408
return gtpb == null ? 0 : gtpb.Length;
411
public override Type ReturnType
413
get { return returnType; }
416
public override ParameterInfo ReturnParameter
418
get { return new ParameterInfoImpl(this, -1); }
421
public override MethodAttributes Attributes
423
get { return attributes; }
426
public void __SetAttributes(MethodAttributes attributes)
428
this.attributes = attributes;
431
public void __SetCallingConvention(CallingConventions callingConvention)
433
this.callingConvention = callingConvention;
434
this.methodSignature = null;
437
public override MethodImplAttributes GetMethodImplementationFlags()
442
private sealed class ParameterInfoImpl : ParameterInfo
444
private readonly MethodBuilder method;
445
private readonly int parameter;
447
internal ParameterInfoImpl(MethodBuilder method, int parameter)
449
this.method = method;
450
this.parameter = parameter;
453
private ParameterBuilder ParameterBuilder
457
if (method.parameters != null)
459
foreach (ParameterBuilder pb in method.parameters)
461
// ParameterBuilder.Position is 1-based
462
if (pb.Position - 1 == parameter)
472
public override string Name
476
ParameterBuilder pb = this.ParameterBuilder;
477
return pb != null ? pb.Name : null;
481
public override Type ParameterType
483
get { return parameter == -1 ? method.returnType : method.parameterTypes[parameter]; }
486
public override ParameterAttributes Attributes
490
ParameterBuilder pb = this.ParameterBuilder;
491
return pb != null ? (ParameterAttributes)pb.Attributes : ParameterAttributes.None;
495
public override int Position
497
get { return parameter; }
500
public override object RawDefaultValue
504
ParameterBuilder pb = this.ParameterBuilder;
505
if (pb != null && (pb.Attributes & (int)ParameterAttributes.HasDefault) != 0)
507
return method.ModuleBuilder.Constant.GetRawConstantValue(method.ModuleBuilder, pb.PseudoToken);
509
if (pb != null && (pb.Attributes & (int)ParameterAttributes.Optional) != 0)
511
return Missing.Value;
517
public override CustomModifiers __GetCustomModifiers()
519
return method.customModifiers.GetParameterCustomModifiers(parameter);
522
public override bool __TryGetFieldMarshal(out FieldMarshal fieldMarshal)
524
fieldMarshal = new FieldMarshal();
528
public override MemberInfo Member
530
get { return method; }
533
public override int MetadataToken
537
ParameterBuilder pb = this.ParameterBuilder;
538
return pb != null ? pb.PseudoToken : 0x08000000;
542
internal override Module Module
544
get { return method.Module; }
548
public override ParameterInfo[] GetParameters()
550
ParameterInfo[] parameters = new ParameterInfo[parameterTypes.Length];
551
for (int i = 0; i < parameters.Length; i++)
553
parameters[i] = new ParameterInfoImpl(this, i);
558
internal override int ParameterCount
560
get { return parameterTypes.Length; }
563
public override Type DeclaringType
565
get { return typeBuilder.IsModulePseudoType ? null : typeBuilder; }
568
public override string Name
573
public override CallingConventions CallingConvention
575
get { return callingConvention; }
578
public override int MetadataToken
580
get { return pseudoToken; }
583
public override bool IsGenericMethod
585
get { return gtpb != null; }
588
public override bool IsGenericMethodDefinition
590
get { return gtpb != null; }
593
public override Module Module
595
get { return typeBuilder.Module; }
598
public Module GetModule()
600
return typeBuilder.Module;
603
public MethodToken GetToken()
605
return new MethodToken(pseudoToken);
608
public override MethodBody GetMethodBody()
610
throw new NotSupportedException();
613
public override int __MethodRVA
615
get { throw new NotImplementedException(); }
618
public bool InitLocals
620
get { return initLocals; }
621
set { initLocals = value; }
624
public void __AddUnmanagedExport(string name, int ordinal)
626
this.ModuleBuilder.AddUnmanagedExport(name, ordinal, this, new RelativeVirtualAddress(0xFFFFFFFF));
629
public void CreateMethodBody(byte[] il, int count)
633
throw new NotSupportedException();
635
if (il.Length != count)
637
Array.Resize(ref il, count);
639
SetMethodBody(il, 16, null, null, null);
642
public void SetMethodBody(byte[] il, int maxStack, byte[] localSignature, IEnumerable<ExceptionHandler> exceptionHandlers, IEnumerable<int> tokenFixups)
644
ByteBuffer bb = this.ModuleBuilder.methodBodies;
646
if (localSignature == null && exceptionHandlers == null && maxStack <= 8 && il.Length < 64)
649
ILGenerator.WriteTinyHeader(bb, il.Length);
653
// fat headers require 4-byte alignment
656
ILGenerator.WriteFatHeader(bb, initLocals, exceptionHandlers != null, (ushort)maxStack, il.Length,
657
localSignature == null ? 0 : this.ModuleBuilder.GetSignatureToken(localSignature, localSignature.Length).Token);
660
if (tokenFixups != null)
662
ILGenerator.AddTokenFixups(bb.Position, this.ModuleBuilder.tokenFixupOffsets, tokenFixups);
666
if (exceptionHandlers != null)
668
List<ILGenerator.ExceptionBlock> exceptions = new List<ILGenerator.ExceptionBlock>();
669
foreach (ExceptionHandler block in exceptionHandlers)
671
exceptions.Add(new ILGenerator.ExceptionBlock(block));
673
ILGenerator.WriteExceptionHandlers(bb, exceptions);
679
this.nameIndex = this.ModuleBuilder.Strings.Add(name);
680
this.signature = this.ModuleBuilder.GetSignatureBlobIndex(this.MethodSignature);
682
__ReleaseILGenerator();
684
if (declarativeSecurity != null)
686
this.ModuleBuilder.AddDeclarativeSecurity(pseudoToken, declarativeSecurity);
690
internal ModuleBuilder ModuleBuilder
692
get { return typeBuilder.ModuleBuilder; }
695
internal void WriteMethodDefRecord(int baseRVA, MetadataWriter mw, ref int paramList)
699
mw.Write(rva + baseRVA);
705
mw.Write((short)implFlags);
706
mw.Write((short)attributes);
707
mw.WriteStringIndex(nameIndex);
708
mw.WriteBlobIndex(signature);
709
mw.WriteParam(paramList);
710
if (parameters != null)
712
paramList += parameters.Count;
716
internal void WriteParamRecords(MetadataWriter mw)
718
if (parameters != null)
720
foreach (ParameterBuilder pb in parameters)
722
pb.WriteParamRecord(mw);
727
internal void FixupToken(int token, ref int parameterToken)
729
typeBuilder.ModuleBuilder.RegisterTokenFixup(this.pseudoToken, token);
730
if (parameters != null)
732
foreach (ParameterBuilder pb in parameters)
734
pb.FixupToken(parameterToken++);
739
internal override MethodSignature MethodSignature
743
if (methodSignature == null)
745
methodSignature = MethodSignature.MakeFromBuilder(returnType, parameterTypes, customModifiers, callingConvention, gtpb == null ? 0 : gtpb.Length);
747
return methodSignature;
751
internal override int ImportTo(ModuleBuilder other)
753
return other.ImportMethodOrField(typeBuilder, name, this.MethodSignature);
756
internal void CheckBaked()
758
typeBuilder.CheckBaked();
761
internal override int GetCurrentToken()
763
if (typeBuilder.ModuleBuilder.IsSaved)
765
return typeBuilder.ModuleBuilder.ResolvePseudoToken(pseudoToken);
773
internal override bool IsBaked
775
get { return typeBuilder.IsBaked; }