b8248a172a3a530aa7f1353284a57275ae3b98d7
[platform/upstream/dotnet/runtime.git] /
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.
4
5 using System.Collections.Generic;
6 using System.Diagnostics;
7 using System.Reflection.Metadata;
8 using System.Runtime.InteropServices;
9
10 namespace System.Reflection.TypeLoading.Ecma
11 {
12     internal readonly struct EcmaMethodDecoder : IMethodDecoder
13     {
14         private readonly MethodDefinitionHandle _handle;
15         private readonly EcmaModule _module;
16
17         internal EcmaMethodDecoder(MethodDefinitionHandle handle, EcmaModule module)
18             : this()
19         {
20             _handle = handle;
21             _module = module;
22             _neverAccessThisExceptThroughMethodDefinitionProperty = handle.GetMethodDefinition(Reader);
23         }
24
25         public RoModule GetRoModule() => _module;
26
27         public string ComputeName() => MethodDefinition.Name.GetString(Reader);
28         public int MetadataToken => _handle.GetToken();
29         public IEnumerable<CustomAttributeData> ComputeTrueCustomAttributes() => MethodDefinition.GetCustomAttributes().ToTrueCustomAttributes(_module);
30
31         public int ComputeGenericParameterCount() => MethodDefinition.GetGenericParameters().Count;
32         public RoType[] ComputeGenericArgumentsOrParameters()
33         {
34             GenericParameterHandleCollection gphs = MethodDefinition.GetGenericParameters();
35             int count = gphs.Count;
36             if (count == 0)
37                 return Array.Empty<RoType>();
38
39             RoType[] gps = new RoType[count];
40             foreach (GenericParameterHandle gph in gphs)
41             {
42                 RoType gp = gph.ResolveGenericParameter(_module);
43                 gps[gp.GenericParameterPosition] = gp;
44             }
45             return gps;
46         }
47
48         public MethodAttributes ComputeAttributes() => MethodDefinition.Attributes;
49
50         public CallingConventions ComputeCallingConvention()
51         {
52             BlobReader signatureBlob = MethodDefinition.Signature.GetBlobReader(Reader);
53             SignatureHeader sigHeader = signatureBlob.ReadSignatureHeader();
54
55             CallingConventions result;
56             if (sigHeader.CallingConvention == SignatureCallingConvention.VarArgs)
57                 result = CallingConventions.VarArgs;
58             else
59                 result = CallingConventions.Standard;
60
61             if (sigHeader.IsInstance)
62                 result |= CallingConventions.HasThis;
63
64             if (sigHeader.HasExplicitThis)
65                 result |= CallingConventions.ExplicitThis;
66
67             return result;
68         }
69
70         public MethodImplAttributes ComputeMethodImplementationFlags() => MethodDefinition.ImplAttributes;
71
72         public MethodSig<RoParameter> SpecializeMethodSig(IRoMethodBase roMethodBase)
73         {
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())
80             {
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);
85             }
86
87             for (int position = -1; position < numParameters; position++)
88             {
89                 Type parameterType = position == -1 ? sig.ReturnType : sig.ParameterTypes[position];
90                 if (methodSig[position] == null)
91                     methodSig[position] = new RoThinMethodParameter(roMethodBase, position, parameterType);
92             }
93
94             return methodSig;
95         }
96
97         public MethodSig<RoType> SpecializeCustomModifiers(in TypeContext typeContext)
98         {
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++)
103             {
104                 RoType roType = position == -1 ? sig.ReturnType : sig.ParameterTypes[position];
105                 methodSig[position] = roType;
106             }
107             return methodSig;
108         }
109
110         public MethodSig<string> SpecializeMethodSigStrings(in TypeContext typeContext)
111         {
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++)
118             {
119                 results[position] = sig.ParameterTypes[position];
120             }
121             return results;
122         }
123
124         public MethodBody SpecializeMethodBody(IRoMethodBase owner)
125         {
126             int rva = MethodDefinition.RelativeVirtualAddress;
127             if (rva == 0)
128                 return null;
129             return new EcmaMethodBody(owner, ((EcmaModule)(owner.MethodBase.Module)).PEReader.GetMethodBody(rva));
130         }
131
132         public DllImportAttribute ComputeDllImportAttribute()
133         {
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
140             {
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.
145             };
146             CallingConvention callConv = (a & MethodImportAttributes.CallingConventionMask) switch
147             {
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(),
154             };
155             return new DllImportAttribute(libraryName)
156             {
157                 EntryPoint = entryPointName,
158                 ExactSpelling = (a & MethodImportAttributes.ExactSpelling) != 0,
159                 CharSet = charSet,
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,
165             };
166         }
167
168         private MetadataReader Reader => _module.Reader;
169         private MetadataLoadContext Loader => GetRoModule().Loader;
170
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;
174     }
175 }