Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add minimal WebCIL support #3184

Merged
merged 3 commits into from
Mar 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ICSharpCode.BamlDecompiler/Baml/KnownThings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ public KnownThings(IDecompilerTypeSystem typeSystem)
}
catch (Exception ex)
{
throw new ICSharpCode.Decompiler.DecompilerException(typeSystem.MainModule.PEFile, ex.Message, ex);
throw new ICSharpCode.Decompiler.DecompilerException(typeSystem.MainModule.MetadataFile, ex.Message, ex);
}
}

Expand Down
12 changes: 6 additions & 6 deletions ICSharpCode.BamlDecompiler/BamlDecompilerTypeSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,16 @@ public class BamlDecompilerTypeSystem : SimpleCompilation, IDecompilerTypeSystem
"System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
};

public BamlDecompilerTypeSystem(PEFile mainModule, IAssemblyResolver assemblyResolver)
public BamlDecompilerTypeSystem(MetadataFile mainModule, IAssemblyResolver assemblyResolver)
{
if (mainModule == null)
throw new ArgumentNullException(nameof(mainModule));
if (assemblyResolver == null)
throw new ArgumentNullException(nameof(assemblyResolver));
// Load referenced assemblies and type-forwarder references.
// This is necessary to make .NET Core/PCL binaries work better.
var referencedAssemblies = new List<PEFile>();
var assemblyReferenceQueue = new Queue<(bool IsAssembly, PEFile MainModule, object Reference)>();
var referencedAssemblies = new List<MetadataFile>();
var assemblyReferenceQueue = new Queue<(bool IsAssembly, MetadataFile MainModule, object Reference)>();
var mainMetadata = mainModule.Metadata;
foreach (var h in mainMetadata.GetModuleReferences())
{
Expand All @@ -73,16 +73,16 @@ public BamlDecompilerTypeSystem(PEFile mainModule, IAssemblyResolver assemblyRes
{
assemblyReferenceQueue.Enqueue((true, mainModule, AssemblyNameReference.Parse(bamlReference)));
}
var comparer = KeyComparer.Create(((bool IsAssembly, PEFile MainModule, object Reference) reference) =>
var comparer = KeyComparer.Create(((bool IsAssembly, MetadataFile MainModule, object Reference) reference) =>
reference.IsAssembly ? "A:" + ((IAssemblyReference)reference.Reference).FullName :
"M:" + reference.Reference);
var processedAssemblyReferences = new HashSet<(bool IsAssembly, PEFile Parent, object Reference)>(comparer);
var processedAssemblyReferences = new HashSet<(bool IsAssembly, MetadataFile Parent, object Reference)>(comparer);
while (assemblyReferenceQueue.Count > 0)
{
var asmRef = assemblyReferenceQueue.Dequeue();
if (!processedAssemblyReferences.Add(asmRef))
continue;
PEFile asm;
MetadataFile asm;
if (asmRef.IsAssembly)
{
asm = assemblyResolver.Resolve((IAssemblyReference)asmRef.Reference);
Expand Down
6 changes: 2 additions & 4 deletions ICSharpCode.BamlDecompiler/Rewrite/ConnectionIdRewritePass.cs
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ void DecompileConnections(XamlContext ctx, List<(LongSet, FieldAssignment)> fiel

IMethod connectMethod = null;
MethodDefinition connectMetadataEntry = default;
var module = ctx.TypeSystem.MainModule.PEFile;
var module = ctx.TypeSystem.MainModule.MetadataFile;

foreach (IMethod m in type.Methods)
{
Expand Down Expand Up @@ -171,9 +171,7 @@ void DecompileConnections(XamlContext ctx, List<(LongSet, FieldAssignment)> fiel

ctx.GeneratedMembers.Add(connectMethod.MetadataToken);



var body = module.Reader.GetMethodBody(connectMetadataEntry.RelativeVirtualAddress);
var body = module.GetMethodBody(connectMetadataEntry.RelativeVirtualAddress);
var genericContext = new GenericContext(
classTypeParameters: connectMethod.DeclaringType?.TypeParameters,
methodTypeParameters: connectMethod.TypeParameters);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System;
using System.Collections.Concurrent;
using System.IO;
using System.Management.Automation;
using System.Threading;
Expand Down Expand Up @@ -89,7 +88,7 @@ protected override void ProcessRecord()

private void DoDecompile(string path)
{
PEFile module = Decompiler.TypeSystem.MainModule.PEFile;
MetadataFile module = Decompiler.TypeSystem.MainModule.MetadataFile;
var assemblyResolver = new UniversalAssemblyResolver(module.FileName, false, module.Metadata.DetectTargetFrameworkId());
WholeProjectDecompiler decompiler = new WholeProjectDecompiler(assemblyResolver);
decompiler.ProgressIndicator = this;
Expand Down
28 changes: 14 additions & 14 deletions ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ public CSharpDecompiler(string fileName, IAssemblyResolver assemblyResolver, Dec
/// <summary>
/// Creates a new <see cref="CSharpDecompiler"/> instance from the given <paramref name="module"/> using the given <paramref name="assemblyResolver"/> and <paramref name="settings"/>.
/// </summary>
public CSharpDecompiler(PEFile module, IAssemblyResolver assemblyResolver, DecompilerSettings settings)
public CSharpDecompiler(MetadataFile module, IAssemblyResolver assemblyResolver, DecompilerSettings settings)
: this(new DecompilerTypeSystem(module, assemblyResolver, settings), settings)
{
}
Expand All @@ -264,7 +264,7 @@ public CSharpDecompiler(DecompilerTypeSystem typeSystem, DecompilerSettings sett
this.typeSystem = typeSystem ?? throw new ArgumentNullException(nameof(typeSystem));
this.settings = settings;
this.module = typeSystem.MainModule;
this.metadata = module.PEFile.Metadata;
this.metadata = module.MetadataFile.Metadata;
if (module.TypeSystemOptions.HasFlag(TypeSystemOptions.Uncached))
throw new ArgumentException("Cannot use an uncached type system in the decompiler.");
}
Expand All @@ -276,7 +276,7 @@ public CSharpDecompiler(DecompilerTypeSystem typeSystem, DecompilerSettings sett
/// <param name="module">The module containing the member.</param>
/// <param name="member">The metadata token/handle of the member. Can be a TypeDef, MethodDef or FieldDef.</param>
/// <param name="settings">THe settings used to determine whether code should be hidden. E.g. if async methods are not transformed, async state machines are included in the decompiled code.</param>
public static bool MemberIsHidden(Metadata.PEFile module, EntityHandle member, DecompilerSettings settings)
public static bool MemberIsHidden(MetadataFile module, EntityHandle member, DecompilerSettings settings)
{
if (module == null || member.IsNil)
return false;
Expand Down Expand Up @@ -539,7 +539,7 @@ IDocumentationProvider CreateDefaultDocumentationProvider()
{
try
{
return XmlDocLoader.LoadDocumentation(module.PEFile);
return XmlDocLoader.LoadDocumentation(module.MetadataFile);
}
catch (System.Xml.XmlException)
{
Expand Down Expand Up @@ -633,7 +633,7 @@ void DoDecompileTypes(IEnumerable<TypeDefinitionHandle> types, DecompileRun deco
var typeDef = module.GetDefinition(typeDefHandle);
if (typeDef.Name == "<Module>" && typeDef.Members.Count == 0)
continue;
if (MemberIsHidden(module.PEFile, typeDefHandle, settings))
if (MemberIsHidden(module.MetadataFile, typeDefHandle, settings))
continue;
if (string.IsNullOrEmpty(typeDef.Namespace))
{
Expand Down Expand Up @@ -702,7 +702,7 @@ public ILTransformContext CreateILTransformContext(ILFunction function)
/// <summary>
/// Determines the "code-mappings" for a given TypeDef or MethodDef. See <see cref="CodeMappingInfo"/> for more information.
/// </summary>
public static CodeMappingInfo GetCodeMappingInfo(PEFile module, EntityHandle member)
public static CodeMappingInfo GetCodeMappingInfo(MetadataFile module, EntityHandle member)
{
var declaringType = (TypeDefinitionHandle)member.GetDeclaringType(module.Metadata);

Expand Down Expand Up @@ -744,7 +744,7 @@ public static CodeMappingInfo GetCodeMappingInfo(PEFile module, EntityHandle mem
return info;
}

private static void ReadCodeMappingInfo(PEFile module, CodeMappingInfo info, MethodDefinitionHandle parent, MethodDefinitionHandle part, Queue<MethodDefinitionHandle> connectedMethods, HashSet<TypeDefinitionHandle> processedNestedTypes)
private static void ReadCodeMappingInfo(MetadataFile module, CodeMappingInfo info, MethodDefinitionHandle parent, MethodDefinitionHandle part, Queue<MethodDefinitionHandle> connectedMethods, HashSet<TypeDefinitionHandle> processedNestedTypes)
{
var md = module.Metadata.GetMethodDefinition(part);

Expand All @@ -756,7 +756,7 @@ private static void ReadCodeMappingInfo(PEFile module, CodeMappingInfo info, Met

var declaringType = md.GetDeclaringType();

var blob = module.Reader.GetMethodBody(md.RelativeVirtualAddress).GetILReader();
var blob = module.GetMethodBody(md.RelativeVirtualAddress).GetILReader();
while (blob.RemainingBytes > 0)
{
var code = blob.DecodeOpCode();
Expand Down Expand Up @@ -1357,7 +1357,7 @@ EntityDeclaration DoDecompile(ITypeDefinition typeDef, DecompileRun decompileRun
// Decompile members that are not compiler-generated.
foreach (var entity in allOrderedEntities)
{
if (entity.MetadataToken.IsNil || MemberIsHidden(module.PEFile, entity.MetadataToken, settings))
if (entity.MetadataToken.IsNil || MemberIsHidden(module.MetadataFile, entity.MetadataToken, settings))
{
continue;
}
Expand Down Expand Up @@ -1403,7 +1403,7 @@ EntityDeclaration DoDecompile(ITypeDefinition typeDef, DecompileRun decompileRun
if (typeDecl.ClassType == ClassType.Enum)
{
Debug.Assert(typeDef.Kind == TypeKind.Enum);
EnumValueDisplayMode displayMode = DetectBestEnumValueDisplayMode(typeDef, module.PEFile);
EnumValueDisplayMode displayMode = DetectBestEnumValueDisplayMode(typeDef, module.MetadataFile);
switch (displayMode)
{
case EnumValueDisplayMode.FirstOnly:
Expand Down Expand Up @@ -1532,7 +1532,7 @@ void DoDecompileMember(IEntity entity, RecordDecompiler recordDecompiler, Partia
}
}

EnumValueDisplayMode DetectBestEnumValueDisplayMode(ITypeDefinition typeDef, PEFile module)
EnumValueDisplayMode DetectBestEnumValueDisplayMode(ITypeDefinition typeDef, MetadataFile module)
{
if (typeDef.HasAttribute(KnownAttribute.Flags))
return EnumValueDisplayMode.AllHex;
Expand Down Expand Up @@ -1608,7 +1608,7 @@ EntityDeclaration DoDecompile(IMethod method, DecompileRun decompileRun, ITypeRe
}
FixParameterNames(methodDecl);
var methodDefinition = metadata.GetMethodDefinition((MethodDefinitionHandle)method.MetadataToken);
if (!settings.LocalFunctions && LocalFunctionDecompiler.LocalFunctionNeedsAccessibilityChange(method.ParentModule.PEFile, (MethodDefinitionHandle)method.MetadataToken))
if (!settings.LocalFunctions && LocalFunctionDecompiler.LocalFunctionNeedsAccessibilityChange(method.ParentModule.MetadataFile, (MethodDefinitionHandle)method.MetadataToken))
{
// if local functions are not active and we're dealing with a local function,
// reduce the visibility of the method to private,
Expand Down Expand Up @@ -1701,7 +1701,7 @@ void DecompileBody(IMethod method, EntityDeclaration entityDecl, DecompileRun de
MethodBodyBlock methodBody;
try
{
methodBody = module.PEFile.Reader.GetMethodBody(methodDef.RelativeVirtualAddress);
methodBody = module.MetadataFile.GetMethodBody(methodDef.RelativeVirtualAddress);
}
catch (BadImageFormatException ex)
{
Expand Down Expand Up @@ -1980,7 +1980,7 @@ EntityDeclaration DoDecompile(IField field, DecompileRun decompileRun, ITypeReso
string message;
try
{
var initVal = fieldDefinition.GetInitialValue(module.PEFile.Reader, TypeSystem);
var initVal = fieldDefinition.GetInitialValue(module.MetadataFile, TypeSystem);
message = string.Format(" Not supported: data({0}) ", BitConverter.ToString(initVal.ReadBytes(initVal.RemainingBytes)).Replace('-', ' '));
}
catch (BadImageFormatException ex)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,6 @@ interface IProjectFileWriter
/// <param name="project">The information about the project being created.</param>
/// <param name="files">A collection of source files to be included into the project.</param>
/// <param name="module">The module being decompiled.</param>
void Write(TextWriter target, IProjectInfoProvider project, IEnumerable<ProjectItemInfo> files, PEFile module);
void Write(TextWriter target, IProjectInfoProvider project, IEnumerable<ProjectItemInfo> files, MetadataFile module);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,10 @@ public void Write(
TextWriter target,
IProjectInfoProvider project,
IEnumerable<ProjectItemInfo> files,
PEFile module)
MetadataFile module)
{
const string ns = "http://schemas.microsoft.com/developer/msbuild/2003";
string platformName = TargetServices.GetPlatformName(module);
string platformName = module is PEFile peFile ? TargetServices.GetPlatformName(peFile) : "AnyCPU";
var targetFramework = TargetServices.DetectTargetFramework(module);
if (targetFramework.Identifier == ".NETFramework" && targetFramework.VersionNumber == 200)
targetFramework = TargetServices.DetectTargetFrameworkNET20(module, project.AssemblyResolver, targetFramework);
Expand Down Expand Up @@ -80,26 +80,22 @@ public void Write(
w.WriteValue(platformName);
w.WriteEndElement(); // </Platform>

if (module.Reader.PEHeaders.IsDll)
{
w.WriteElementString("OutputType", "Library");
}
else
string outputType;

switch ((module as PEFile)?.Reader.PEHeaders.PEHeader.Subsystem)
{
switch (module.Reader.PEHeaders.PEHeader.Subsystem)
{
case Subsystem.WindowsGui:
w.WriteElementString("OutputType", "WinExe");
break;
case Subsystem.WindowsCui:
w.WriteElementString("OutputType", "Exe");
break;
default:
w.WriteElementString("OutputType", "Library");
break;
}
case Subsystem.WindowsGui:
outputType = "WinExe";
break;
case Subsystem.WindowsCui:
outputType = "Exe";
break;
default:
outputType = "Library";
break;
}

w.WriteElementString("OutputType", outputType);
w.WriteElementString("LangVersion", project.LanguageVersion.ToString().Replace("CSharp", "").Replace('_', '.'));

w.WriteElementString("AssemblyName", module.Name);
Expand All @@ -123,7 +119,8 @@ public void Write(
w.WriteStartElement("PropertyGroup"); // platform-specific
w.WriteAttributeString("Condition", " '$(Platform)' == '" + platformName + "' ");
w.WriteElementString("PlatformTarget", platformName);
if (targetFramework.VersionNumber > 400 && platformName == "AnyCPU" && (module.Reader.PEHeaders.CorHeader.Flags & CorFlags.Prefers32Bit) == 0)
if (targetFramework.VersionNumber > 400 && platformName == "AnyCPU"
&& ((module as PEFile)?.Reader.PEHeaders.CorHeader.Flags & CorFlags.Prefers32Bit) == 0)
{
w.WriteElementString("Prefer32Bit", "false");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public void Write(
TextWriter target,
IProjectInfoProvider project,
IEnumerable<ProjectItemInfo> files,
PEFile module)
MetadataFile module)
{
using (XmlTextWriter xmlWriter = new XmlTextWriter(target))
{
Expand All @@ -76,7 +76,7 @@ public void Write(
}
}

static void Write(XmlTextWriter xml, IProjectInfoProvider project, IEnumerable<ProjectItemInfo> files, PEFile module)
static void Write(XmlTextWriter xml, IProjectInfoProvider project, IEnumerable<ProjectItemInfo> files, MetadataFile module)
{
xml.WriteStartElement("Project");

Expand Down Expand Up @@ -105,18 +105,30 @@ static void PlaceIntoTag(string tagName, XmlTextWriter xml, Action content)
}
}

static void WriteAssemblyInfo(XmlTextWriter xml, PEFile module, IProjectInfoProvider project, ProjectType projectType)
static void WriteAssemblyInfo(XmlTextWriter xml, MetadataFile module, IProjectInfoProvider project, ProjectType projectType)
{
xml.WriteElementString("AssemblyName", module.Name);

// Since we create AssemblyInfo.cs manually, we need to disable the auto-generation
xml.WriteElementString("GenerateAssemblyInfo", FalseString);

WriteOutputType(xml, module.Reader.PEHeaders.IsDll, module.Reader.PEHeaders.PEHeader.Subsystem, projectType);
string platformName;
CorFlags flags;
if (module is PEFile { Reader.PEHeaders: var headers } peFile)
{
WriteOutputType(xml, headers.IsDll, headers.PEHeader.Subsystem, projectType);
platformName = TargetServices.GetPlatformName(peFile);
flags = headers.CorHeader.Flags;
}
else
{
WriteOutputType(xml, isDll: true, Subsystem.Unknown, projectType);
platformName = AnyCpuString;
flags = 0;
}

WriteDesktopExtensions(xml, projectType);

string platformName = TargetServices.GetPlatformName(module);
var targetFramework = TargetServices.DetectTargetFramework(module);
if (targetFramework.Identifier == ".NETFramework" && targetFramework.VersionNumber == 200)
targetFramework = TargetServices.DetectTargetFrameworkNET20(module, project.AssemblyResolver, targetFramework);
Expand All @@ -134,7 +146,7 @@ static void WriteAssemblyInfo(XmlTextWriter xml, PEFile module, IProjectInfoProv
xml.WriteElementString("PlatformTarget", platformName);
}

if (platformName == AnyCpuString && (module.Reader.PEHeaders.CorHeader.Flags & CorFlags.Prefers32Bit) != 0)
if (platformName == AnyCpuString && (flags & CorFlags.Prefers32Bit) != 0)
{
xml.WriteElementString("Prefer32Bit", TrueString);
}
Expand Down Expand Up @@ -238,7 +250,7 @@ static void WriteResources(XmlTextWriter xml, IEnumerable<ProjectItemInfo> files
}
}

static void WriteReferences(XmlTextWriter xml, PEFile module, IProjectInfoProvider project, ProjectType projectType)
static void WriteReferences(XmlTextWriter xml, MetadataFile module, IProjectInfoProvider project, ProjectType projectType)
{
bool isNetCoreApp = TargetServices.DetectTargetFramework(module).Identifier == ".NETCoreApp";
var targetPacks = new HashSet<string>();
Expand Down Expand Up @@ -292,7 +304,7 @@ static string GetSdkString(ProjectType projectType)
}
}

static ProjectType GetProjectType(PEFile module)
static ProjectType GetProjectType(MetadataFile module)
{
foreach (var referenceName in module.AssemblyReferences.Select(r => r.Name))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ static class TargetServices
/// <param name="module">The module to get the target framework description for. Cannot be null.</param>
/// <returns>A new instance of the <see cref="TargetFramework"/> class that describes the specified <paramref name="module"/>.
/// </returns>
public static TargetFramework DetectTargetFramework(PEFile module)
public static TargetFramework DetectTargetFramework(MetadataFile module)
{
if (module is null)
{
Expand Down Expand Up @@ -216,17 +216,17 @@ public static string GetPlatformName(PEFile module)
};

/// <summary>
/// Gets exact <see cref="TargetFramework"/> if <see cref="PEFile.GetRuntime"/> is <see cref="TargetRuntime.Net_2_0"/>
/// Gets exact <see cref="TargetFramework"/> if <see cref="MetadataFile.GetRuntime"/> is <see cref="TargetRuntime.Net_2_0"/>
/// </summary>
public static TargetFramework DetectTargetFrameworkNET20(PEFile module, IAssemblyResolver assemblyResolver, TargetFramework targetFramework)
public static TargetFramework DetectTargetFrameworkNET20(MetadataFile module, IAssemblyResolver assemblyResolver, TargetFramework targetFramework)
{
var resolvedAssemblies = new HashSet<string>();
int version = 200;
GetFrameworkVersionNET20(module, assemblyResolver, resolvedAssemblies, ref version);
return new TargetFramework(targetFramework.Identifier, version, targetFramework.Profile);
}

static void GetFrameworkVersionNET20(PEFile module, IAssemblyResolver assemblyResolver, HashSet<string> resolvedAssemblies, ref int version)
static void GetFrameworkVersionNET20(MetadataFile module, IAssemblyResolver assemblyResolver, HashSet<string> resolvedAssemblies, ref int version)
{
foreach (var r in module.Metadata.AssemblyReferences)
{
Expand All @@ -245,7 +245,7 @@ static void GetFrameworkVersionNET20(PEFile module, IAssemblyResolver assemblyRe
break;
}

PEFile resolvedReference;
MetadataFile resolvedReference;
try
{
resolvedReference = assemblyResolver.Resolve(reference);
Expand Down
Loading
Loading