diff --git a/ICSharpCode.Decompiler/IL/ILReader.cs b/ICSharpCode.Decompiler/IL/ILReader.cs index a31707a45..ff0a46b9e 100644 --- a/ICSharpCode.Decompiler/IL/ILReader.cs +++ b/ICSharpCode.Decompiler/IL/ILReader.cs @@ -28,6 +28,7 @@ using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.Util; using ArrayType = ICSharpCode.Decompiler.TypeSystem.ArrayType; using ByReferenceType = ICSharpCode.Decompiler.TypeSystem.ByReferenceType; +using PinnedType = ICSharpCode.Decompiler.TypeSystem.Implementation.PinnedType; using ICSharpCode.Decompiler.Disassembler; using System.Reflection.Metadata.Ecma335; @@ -53,7 +54,6 @@ namespace ICSharpCode.Decompiler.IL IMethod method; MethodBodyBlock body; Metadata.IDebugInfoProvider debugInfo; - ITypeResolveContext resolveContext; MethodSignature methodSignature; StackType methodReturnStackType; BlobReader reader; @@ -86,8 +86,7 @@ namespace ICSharpCode.Decompiler.IL this.currentStack = ImmutableStack.Empty; this.unionFind = new UnionFind(); this.stackMismatchPairs = new List<(ILVariable, ILVariable)>(); - this.resolveContext = new SimpleTypeResolveContext(this.method); - this.methodReturnStackType = TypeSystem.Implementation.DynamicAwareTypeReference.Create(methodSignature.ReturnType, methodDefinition.GetCustomAttributes(), metadata).Resolve(resolveContext).GetStackType(); + this.methodReturnStackType = typeSystem.ResolveFromSignature(TypeSystem.Implementation.DynamicAwareTypeReference.Create(methodSignature.ReturnType, methodDefinition.GetCustomAttributes(), metadata)).GetStackType(); InitParameterVariables(); localVariables = InitLocalVariables(); if (body.LocalVariablesInitialized) { @@ -140,7 +139,12 @@ namespace ICSharpCode.Decompiler.IL void InitParameterVariables() { - parameterVariables = new ILVariable[GetPopCount(OpCode.Call, method)]; + int popCount = method.Parameters.Count; + if (!method.IsStatic) + popCount++; + if (method.Parameters.LastOrDefault()?.Type == SpecialType.ArgList) + popCount--; + parameterVariables = new ILVariable[popCount]; int paramIndex = 0; int offset = 0; if (methodSignature.Header.IsInstance) { offset = 1; @@ -154,10 +158,17 @@ namespace ICSharpCode.Decompiler.IL Debug.Assert(paramIndex == parameterVariables.Length); } - ILVariable CreateILVariable(int index, ITypeReference type) + ILVariable CreateILVariable(int index, ITypeReference typeRef) { - VariableKind kind = IsPinned(type) ? VariableKind.PinnedLocal : VariableKind.Local; - ILVariable ilVar = new ILVariable(kind, type.Resolve(resolveContext), index); + IType type = typeSystem.ResolveFromSignature(typeRef); + VariableKind kind; + if (type is PinnedType pinned) { + kind = VariableKind.PinnedLocal; + type = pinned.ElementType; + } else { + kind = VariableKind.Local; + } + ILVariable ilVar = new ILVariable(kind, type, index); if (!UseDebugSymbols || debugInfo == null || !debugInfo.TryGetName((MethodDefinitionHandle)method.MetadataToken, index, out string name)) { ilVar.Name = "V_" + index; ilVar.HasGeneratedName = true; @@ -170,14 +181,13 @@ namespace ICSharpCode.Decompiler.IL return ilVar; } - bool IsPinned(ITypeReference type) - { - return type is TypeSystem.Implementation.PinnedTypeReference; - } - ILVariable CreateILVariable(int index, ITypeReference typeReference, string name) { - IType parameterType = typeReference.Resolve(resolveContext); + IType parameterType = typeSystem.ResolveFromSignature(typeReference); + ITypeDefinition def = parameterType.GetDefinition(); + if (def != null && index < 0 && def.IsReferenceType == false) { + parameterType = new ByReferenceType(parameterType); + } Debug.Assert(!parameterType.IsUnbound()); if (parameterType.IsUnbound()) { // parameter types should not be unbound, the only known cause for these is a Cecil bug: @@ -1288,12 +1298,12 @@ namespace ICSharpCode.Decompiler.IL var parameterTypes = new IType[signature.ParameterTypes.Length]; var arguments = new ILInstruction[parameterTypes.Length]; for (int i = signature.ParameterTypes.Length - 1; i >= 0; i--) { - parameterTypes[i] = signature.ParameterTypes[i].Resolve(resolveContext); + parameterTypes[i] = typeSystem.ResolveFromSignature(signature.ParameterTypes[i]); arguments[i] = Pop(parameterTypes[i].GetStackType()); } var call = new CallIndirect( signature.Header.CallingConvention, - signature.ReturnType.Resolve(resolveContext), + typeSystem.ResolveFromSignature(signature.ReturnType), parameterTypes.ToImmutableArray(), arguments, functionPointer @@ -1304,14 +1314,6 @@ namespace ICSharpCode.Decompiler.IL return call; } - static int GetPopCount(OpCode callCode, IMethod method) - { - int popCount = method.Parameters.Count; - if (callCode != OpCode.NewObj && !method.IsStatic) - popCount++; - return popCount; - } - ILInstruction Comparison(ComparisonKind kind, bool un = false) { var right = Pop(); diff --git a/ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs b/ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs index 7179b57f3..e6bad1e52 100644 --- a/ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs +++ b/ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs @@ -98,46 +98,10 @@ namespace ICSharpCode.Decompiler.TypeSystem entityDict[entity] = mr; } - /* - Metadata.IMetadataEntity GetMetadata(IUnresolvedEntity member) + public IType ResolveFromSignature(ITypeReference typeReference) { - if (member == null) - return null; - lock (entityDict) { - if (entityDict.TryGetValue(member, out var mr)) - return mr; - return null; - } - } - - /// - /// Retrieves the Cecil member definition for the specified member. - /// - /// - /// Returns null if the member is not defined in the module being decompiled. - /// - public Metadata.IMetadataEntity GetMetadata(IMember member) - { - if (member == null) - return null; - return GetMetadata(member.UnresolvedMember); - } - - - /// - /// Retrieves the Cecil type definition. - /// - /// - /// Returns null if the type is not defined in the module being decompiled. - /// - public Metadata.TypeDefinition GetMetadata(ITypeDefinition typeDefinition) - { - if (typeDefinition == null) - return default; - return (Metadata.TypeDefinition)GetMetadata(typeDefinition.Parts[0]); + return typeReference.Resolve(context); } - */ - public IMember ResolveAsMember(SRM.EntityHandle memberReference) { @@ -208,21 +172,13 @@ namespace ICSharpCode.Decompiler.TypeSystem var memberRef = metadata.GetMemberReference((SRM.MemberReferenceHandle)fieldReference); Debug.Assert(memberRef.GetKind() == SRM.MemberReferenceKind.Field); declaringType = ResolveAsType(memberRef.Parent); - switch (memberRef.Parent.Kind) { - case SRM.HandleKind.TypeReference: - field = FindNonGenericField(metadata, memberRef, declaringType); - break; - case SRM.HandleKind.TypeSpecification: - throw new NotImplementedException(); - /*if (fieldReference.DeclaringType.IsGenericInstance) { - var git = (GenericInstanceType)fieldReference.DeclaringType; - var typeArguments = git.GenericArguments.SelectArray(Resolve); - field = (IField)field.Specialize(new TypeParameterSubstitution(typeArguments, null)); - }*/ - default: - throw new NotSupportedException(); - } + field = FindNonGenericField(metadata, memberRef, declaringType); break; + default: + throw new NotSupportedException(); + } + if (declaringType.TypeArguments.Count > 0) { + field = (IField)field.Specialize(new TypeParameterSubstitution(declaringType.TypeArguments, null)); } fieldLookupCache.Add(fieldReference, field); } @@ -246,6 +202,7 @@ namespace ICSharpCode.Decompiler.TypeSystem IField CreateFakeField(IType declaringType, string name, ITypeReference returnType) { + Debug.Assert(false, $"Creating fake field for {name}!"); var f = new DefaultUnresolvedField(); f.Name = name; f.ReturnType = returnType; @@ -281,13 +238,25 @@ namespace ICSharpCode.Decompiler.TypeSystem IType declaringType; IReadOnlyList classTypeArguments = null; IReadOnlyList methodTypeArguments = null; + SRM.MethodSignature? signature = null; if (!methodLookupCache.TryGetValue(methodReference, out method)) { var metadata = moduleDefinition.GetMetadataReader(); switch (methodReference.Kind) { case SRM.HandleKind.MethodDefinition: - case SRM.HandleKind.MemberReference: + var methodDef = metadata.GetMethodDefinition((SRM.MethodDefinitionHandle)methodReference); + signature = methodDef.DecodeSignature(TypeReferenceSignatureDecoder.Instance, default); method = FindNonGenericMethod(metadata, methodReference, out declaringType); break; + case SRM.HandleKind.MemberReference: + var memberRef = metadata.GetMemberReference((SRM.MemberReferenceHandle)methodReference); + Debug.Assert(memberRef.GetKind() == SRM.MemberReferenceKind.Method); + signature = memberRef.DecodeMethodSignature(TypeReferenceSignatureDecoder.Instance, default); + var elementMethod = methodReference; + if (memberRef.Parent.Kind == SRM.HandleKind.MethodDefinition) { + elementMethod = (SRM.MethodDefinitionHandle)memberRef.Parent; + } + method = FindNonGenericMethod(metadata, elementMethod, out declaringType); + break; case SRM.HandleKind.MethodSpecification: var methodSpec = metadata.GetMethodSpecification((SRM.MethodSpecificationHandle)methodReference); method = FindNonGenericMethod(metadata, methodSpec.Method, out declaringType); @@ -299,6 +268,9 @@ namespace ICSharpCode.Decompiler.TypeSystem default: throw new NotSupportedException(); } + if (signature?.Header.CallingConvention == SRM.SignatureCallingConvention.VarArgs) { + method = new VarArgInstanceMethod(method, signature.Value.ParameterTypes.Skip(signature.Value.RequiredParameterCount).Select(p => p.Resolve(context))); + } if (declaringType.TypeArguments.Count > 0) { classTypeArguments = declaringType.TypeArguments.ToList(); } @@ -338,8 +310,15 @@ namespace ICSharpCode.Decompiler.TypeSystem case SRM.HandleKind.MemberReference: var memberRef = metadata.GetMemberReference((SRM.MemberReferenceHandle)methodReference); Debug.Assert(memberRef.GetKind() == SRM.MemberReferenceKind.Method); - declaringType = ResolveAsType(memberRef.Parent); // TODO : Support other handles + switch (memberRef.Parent.Kind) { + case SRM.HandleKind.MethodDefinition: + FindNonGenericMethod(metadata, memberRef.Parent, out declaringType); + break; + default: + declaringType = ResolveAsType(memberRef.Parent); + break; + } declaringTypeDefinition = declaringType.GetDefinition(); var signature = memberRef.DecodeMethodSignature(TypeReferenceSignatureDecoder.Instance, default); if (declaringTypeDefinition == null) { @@ -407,7 +386,7 @@ namespace ICSharpCode.Decompiler.TypeSystem /// IMethod CreateFakeMethod(IType declaringType, string name, SRM.MethodSignature signature) { - Debug.Assert(false, $"Creating fake method for {name}!"); + Debug.Assert(declaringType is ArrayType, $"Creating fake method for {name}!"); var m = new DefaultUnresolvedMethod(); if (name == ".ctor" || name == ".cctor") m.SymbolKind = SymbolKind.Constructor; @@ -416,7 +395,6 @@ namespace ICSharpCode.Decompiler.TypeSystem m.ReturnType = signature.ReturnType; m.IsStatic = !signature.Header.IsInstance; - ITypeReference declaringTypeReference; lock (typeReferenceCecilLoader) { var metadata = moduleDefinition.GetMetadataReader(); for (int i = 0; i < signature.GenericParameterCount; i++) { diff --git a/ICSharpCode.Decompiler/TypeSystem/IDecompilerTypeSystem.cs b/ICSharpCode.Decompiler/TypeSystem/IDecompilerTypeSystem.cs index 34e42be69..427712021 100644 --- a/ICSharpCode.Decompiler/TypeSystem/IDecompilerTypeSystem.cs +++ b/ICSharpCode.Decompiler/TypeSystem/IDecompilerTypeSystem.cs @@ -27,7 +27,8 @@ namespace ICSharpCode.Decompiler.TypeSystem public interface IDecompilerTypeSystem { ICompilation Compilation { get; } - + + IType ResolveFromSignature(ITypeReference typeReference); IType ResolveAsType(EntityHandle typeReference); IField ResolveAsField(EntityHandle fieldReference); IMethod ResolveAsMethod(EntityHandle methodReference); diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/TypeSpecification.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/TypeSpecification.cs index fc875d1fc..bffc03d80 100644 --- a/ICSharpCode.Decompiler/TypeSystem/Implementation/TypeSpecification.cs +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/TypeSpecification.cs @@ -189,6 +189,26 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation } } + sealed class TypeDefTokenTypeReference : ITypeReference + { + readonly SRM.EntityHandle token; + + public TypeDefTokenTypeReference(SRM.EntityHandle token) + { + if (token.Kind != SRM.HandleKind.TypeDefinition) + throw new ArgumentException(nameof(token), "must be TypeDef token"); + this.token = token; + } + + public IType Resolve(ITypeResolveContext context) + { + ITypeDefinition td = context.CurrentAssembly.ResolveTypeDefToken(token); + if (td != null) + return td; + return SpecialType.UnknownType; + } + } + class TypeReferenceSignatureDecoder : SRM.ISignatureTypeProvider { public static readonly TypeReferenceSignatureDecoder Instance = new TypeReferenceSignatureDecoder(); @@ -252,7 +272,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation public ITypeReference GetTypeFromDefinition(SRM.MetadataReader reader, SRM.TypeDefinitionHandle handle, byte rawTypeKind) { - return new GetClassTypeReference(handle.GetFullTypeName(reader), DefaultAssemblyReference.CurrentAssembly); + return new TypeDefTokenTypeReference(handle); } public ITypeReference GetTypeFromReference(SRM.MetadataReader reader, SRM.TypeReferenceHandle handle, byte rawTypeKind) diff --git a/ICSharpCode.Decompiler/TypeSystem/MetadataLoader.cs b/ICSharpCode.Decompiler/TypeSystem/MetadataLoader.cs index 025200d2f..5d8c3615e 100644 --- a/ICSharpCode.Decompiler/TypeSystem/MetadataLoader.cs +++ b/ICSharpCode.Decompiler/TypeSystem/MetadataLoader.cs @@ -313,26 +313,6 @@ namespace ICSharpCode.Decompiler.TypeSystem throw new NotSupportedException(); } } - - sealed class TypeDefTokenTypeReference : ITypeReference - { - readonly EntityHandle token; - - public TypeDefTokenTypeReference(EntityHandle token) - { - if (token.Kind != HandleKind.TypeDefinition) - throw new ArgumentException(nameof(token), "must be TypeDef token"); - this.token = token; - } - - public IType Resolve(ITypeResolveContext context) - { - ITypeDefinition td = context.CurrentAssembly.ResolveTypeDefToken(token); - if (td != null) - return td; - return SpecialType.UnknownType; - } - } #endregion #region Read Attributes diff --git a/ICSharpCode.Decompiler/TypeSystem/SpecializingDecompilerTypeSystem.cs b/ICSharpCode.Decompiler/TypeSystem/SpecializingDecompilerTypeSystem.cs index 9867149d0..c08c12972 100644 --- a/ICSharpCode.Decompiler/TypeSystem/SpecializingDecompilerTypeSystem.cs +++ b/ICSharpCode.Decompiler/TypeSystem/SpecializingDecompilerTypeSystem.cs @@ -53,6 +53,11 @@ namespace ICSharpCode.Decompiler.TypeSystem get { return substitution; } } + public IType ResolveFromSignature(ITypeReference typeReference) + { + return context.ResolveFromSignature(typeReference).AcceptVisitor(substitution); + } + public IType ResolveAsType(System.Reflection.Metadata.EntityHandle typeReference) { return context.ResolveAsType(typeReference).AcceptVisitor(substitution);