1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
5 using System.Collections.Generic;
6 using System.Diagnostics;
7 using System.Reflection.Metadata;
8 using System.Runtime.InteropServices;
10 namespace System.Reflection.TypeLoading.Ecma
12 internal readonly struct EcmaMethodDecoder : IMethodDecoder
14 private readonly MethodDefinitionHandle _handle;
15 private readonly EcmaModule _module;
17 internal EcmaMethodDecoder(MethodDefinitionHandle handle, EcmaModule module)
22 _neverAccessThisExceptThroughMethodDefinitionProperty = handle.GetMethodDefinition(Reader);
25 public RoModule GetRoModule() => _module;
27 public string ComputeName() => MethodDefinition.Name.GetString(Reader);
28 public int MetadataToken => _handle.GetToken();
29 public IEnumerable<CustomAttributeData> ComputeTrueCustomAttributes() => MethodDefinition.GetCustomAttributes().ToTrueCustomAttributes(_module);
31 public int ComputeGenericParameterCount() => MethodDefinition.GetGenericParameters().Count;
32 public RoType[] ComputeGenericArgumentsOrParameters()
34 GenericParameterHandleCollection gphs = MethodDefinition.GetGenericParameters();
35 int count = gphs.Count;
37 return Array.Empty<RoType>();
39 RoType[] gps = new RoType[count];
40 foreach (GenericParameterHandle gph in gphs)
42 RoType gp = gph.ResolveGenericParameter(_module);
43 gps[gp.GenericParameterPosition] = gp;
48 public MethodAttributes ComputeAttributes() => MethodDefinition.Attributes;
50 public CallingConventions ComputeCallingConvention()
52 BlobReader signatureBlob = MethodDefinition.Signature.GetBlobReader(Reader);
53 SignatureHeader sigHeader = signatureBlob.ReadSignatureHeader();
55 CallingConventions result;
56 if (sigHeader.CallingConvention == SignatureCallingConvention.VarArgs)
57 result = CallingConventions.VarArgs;
59 result = CallingConventions.Standard;
61 if (sigHeader.IsInstance)
62 result |= CallingConventions.HasThis;
64 if (sigHeader.HasExplicitThis)
65 result |= CallingConventions.ExplicitThis;
70 public MethodImplAttributes ComputeMethodImplementationFlags() => MethodDefinition.ImplAttributes;
72 public MethodSig<RoParameter> SpecializeMethodSig(IRoMethodBase roMethodBase)
74 MetadataReader reader = Reader;
75 MethodDefinition methodDefiniton = MethodDefinition;
76 MethodSignature<RoType> sig = methodDefiniton.DecodeSignature(_module, roMethodBase.TypeContext);
77 int numParameters = sig.RequiredParameterCount;
78 MethodSig<RoParameter> methodSig = new MethodSig<RoParameter>(numParameters);
79 foreach (ParameterHandle ph in methodDefiniton.GetParameters())
81 Parameter p = ph.GetParameter(reader);
82 int position = p.SequenceNumber - 1;
83 Type parameterType = position == -1 ? sig.ReturnType : sig.ParameterTypes[position];
84 methodSig[position] = new EcmaFatMethodParameter(roMethodBase, position, parameterType, ph);
87 for (int position = -1; position < numParameters; position++)
89 Type parameterType = position == -1 ? sig.ReturnType : sig.ParameterTypes[position];
90 if (methodSig[position] == null)
91 methodSig[position] = new RoThinMethodParameter(roMethodBase, position, parameterType);
97 public MethodSig<RoType> SpecializeCustomModifiers(in TypeContext typeContext)
99 MethodSignature<RoType> sig = MethodDefinition.DecodeSignature(new EcmaModifiedTypeProvider(_module), typeContext);
100 int numParameters = sig.RequiredParameterCount;
101 MethodSig<RoType> methodSig = new MethodSig<RoType>(numParameters);
102 for (int position = -1; position < numParameters; position++)
104 RoType roType = position == -1 ? sig.ReturnType : sig.ParameterTypes[position];
105 methodSig[position] = roType;
110 public MethodSig<string> SpecializeMethodSigStrings(in TypeContext typeContext)
112 ISignatureTypeProvider<string, TypeContext> typeProvider = EcmaSignatureTypeProviderForToString.Instance;
113 MethodSignature<string> sig = MethodDefinition.DecodeSignature(typeProvider, typeContext);
114 int parameterCount = sig.ParameterTypes.Length;
115 MethodSig<string> results = new MethodSig<string>(parameterCount);
116 results[-1] = sig.ReturnType;
117 for (int position = 0; position < parameterCount; position++)
119 results[position] = sig.ParameterTypes[position];
124 public MethodBody SpecializeMethodBody(IRoMethodBase owner)
126 int rva = MethodDefinition.RelativeVirtualAddress;
129 return new EcmaMethodBody(owner, ((EcmaModule)(owner.MethodBase.Module)).PEReader.GetMethodBody(rva));
132 public DllImportAttribute ComputeDllImportAttribute()
134 MetadataReader reader = Reader;
135 MethodImport mi = MethodDefinition.GetImport();
136 string libraryName = mi.Module.GetModuleReference(reader).Name.GetString(reader);
137 string entryPointName = mi.Name.GetString(reader);
138 MethodImportAttributes a = mi.Attributes;
139 CharSet charSet = (a & MethodImportAttributes.CharSetMask) switch
141 MethodImportAttributes.CharSetAnsi => CharSet.Ansi,
142 MethodImportAttributes.CharSetAuto => CharSet.Auto,
143 MethodImportAttributes.CharSetUnicode => CharSet.Unicode,
144 _ => CharSet.None, // Note: CharSet.None is actually the typical case, not an error case.
146 CallingConvention callConv = (a & MethodImportAttributes.CallingConventionMask) switch
148 MethodImportAttributes.CallingConventionCDecl => CallingConvention.Cdecl,
149 MethodImportAttributes.CallingConventionFastCall => CallingConvention.FastCall,
150 MethodImportAttributes.CallingConventionStdCall => CallingConvention.StdCall,
151 MethodImportAttributes.CallingConventionThisCall => CallingConvention.ThisCall,
152 MethodImportAttributes.CallingConventionWinApi => CallingConvention.Winapi,
153 _ => throw new BadImageFormatException(),
155 return new DllImportAttribute(libraryName)
157 EntryPoint = entryPointName,
158 ExactSpelling = (a & MethodImportAttributes.ExactSpelling) != 0,
160 CallingConvention = callConv,
161 PreserveSig = (ComputeMethodImplementationFlags() & MethodImplAttributes.PreserveSig) != 0,
162 SetLastError = (a & MethodImportAttributes.SetLastError) != 0,
163 BestFitMapping = (a & MethodImportAttributes.BestFitMappingMask) == MethodImportAttributes.BestFitMappingEnable,
164 ThrowOnUnmappableChar = (a & MethodImportAttributes.ThrowOnUnmappableCharMask) == MethodImportAttributes.ThrowOnUnmappableCharEnable,
168 private MetadataReader Reader => _module.Reader;
169 private MetadataLoadContext Loader => GetRoModule().Loader;
171 private MethodDefinition MethodDefinition { get { Loader.DisposeCheck(); return _neverAccessThisExceptThroughMethodDefinitionProperty; } }
172 [DebuggerBrowsable(DebuggerBrowsableState.Never)] // Block from debugger watch windows so they don't AV the debugged process.
173 private readonly MethodDefinition _neverAccessThisExceptThroughMethodDefinitionProperty;