Browse Source

Merge pull request #2546 from icsharpcode/mcs5

Mcs5
pull/2553/head
Siegfried Pammer 4 years ago committed by GitHub
parent
commit
65792dfa5e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 16
      ICSharpCode.Decompiler.Tests/CorrectnessTestRunner.cs
  2. 2
      ICSharpCode.Decompiler.Tests/Helpers/Tester.VB.cs
  3. 29
      ICSharpCode.Decompiler.Tests/Helpers/Tester.cs
  4. 6
      ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs
  5. 12
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.cs
  6. 2
      ICSharpCode.Decompiler/CSharp/Transforms/IntroduceUsingDeclarations.cs
  7. 46
      ICSharpCode.Decompiler/IL/ControlFlow/YieldReturnDecompiler.cs
  8. 2
      ICSharpCode.Decompiler/IL/Transforms/SwitchOnStringTransform.cs
  9. 2
      ILSpy-tests

16
ICSharpCode.Decompiler.Tests/CorrectnessTestRunner.cs

@ -75,8 +75,10 @@ namespace ICSharpCode.Decompiler.Tests
CompilerOptions.Optimize | CompilerOptions.UseRoslyn3_11_0, CompilerOptions.Optimize | CompilerOptions.UseRoslyn3_11_0,
CompilerOptions.UseRoslynLatest, CompilerOptions.UseRoslynLatest,
CompilerOptions.Optimize | CompilerOptions.UseRoslynLatest, CompilerOptions.Optimize | CompilerOptions.UseRoslynLatest,
CompilerOptions.UseMcs, CompilerOptions.UseMcs2_6_4,
CompilerOptions.Optimize | CompilerOptions.UseMcs CompilerOptions.Optimize | CompilerOptions.UseMcs2_6_4,
CompilerOptions.UseMcs5_23,
CompilerOptions.Optimize | CompilerOptions.UseMcs5_23
}; };
static readonly CompilerOptions[] roslynOnlyOptions = static readonly CompilerOptions[] roslynOnlyOptions =
@ -286,7 +288,7 @@ namespace ICSharpCode.Decompiler.Tests
[Test] [Test]
public void UnsafeCode([ValueSource(nameof(defaultOptions))] CompilerOptions options) public void UnsafeCode([ValueSource(nameof(defaultOptions))] CompilerOptions options)
{ {
if (options.HasFlag(CompilerOptions.UseMcs)) if (options.HasFlag(CompilerOptions.UseMcs2_6_4))
{ {
Assert.Ignore("Decompiler bug with mono!"); Assert.Ignore("Decompiler bug with mono!");
} }
@ -314,7 +316,7 @@ namespace ICSharpCode.Decompiler.Tests
[Test] [Test]
public void YieldReturn([ValueSource(nameof(defaultOptions))] CompilerOptions options) public void YieldReturn([ValueSource(nameof(defaultOptions))] CompilerOptions options)
{ {
if (options.HasFlag(CompilerOptions.UseMcs)) if ((options & CompilerOptions.UseMcsMask) != 0)
{ {
Assert.Ignore("Decompiler bug with mono!"); Assert.Ignore("Decompiler bug with mono!");
} }
@ -348,7 +350,7 @@ namespace ICSharpCode.Decompiler.Tests
[Test] [Test]
public void MiniJSON([ValueSource(nameof(defaultOptions))] CompilerOptions options) public void MiniJSON([ValueSource(nameof(defaultOptions))] CompilerOptions options)
{ {
if (options.HasFlag(CompilerOptions.UseMcs)) if (options.HasFlag(CompilerOptions.UseMcs2_6_4))
{ {
Assert.Ignore("Decompiler bug with mono!"); Assert.Ignore("Decompiler bug with mono!");
} }
@ -366,12 +368,12 @@ namespace ICSharpCode.Decompiler.Tests
outputFile = Tester.CompileCSharp(Path.Combine(TestCasePath, testFileName), options, outputFile = Tester.CompileCSharp(Path.Combine(TestCasePath, testFileName), options,
outputFileName: Path.Combine(TestCasePath, testOutputFileName)); outputFileName: Path.Combine(TestCasePath, testOutputFileName));
string decompiledCodeFile = Tester.DecompileCSharp(outputFile.PathToAssembly, Tester.GetSettings(options)); string decompiledCodeFile = Tester.DecompileCSharp(outputFile.PathToAssembly, Tester.GetSettings(options));
if (options.HasFlag(CompilerOptions.UseMcs)) if ((options & CompilerOptions.UseMcsMask) != 0)
{ {
// For second pass, use roslyn instead of mcs. // For second pass, use roslyn instead of mcs.
// mcs has some compiler bugs that cause it to not accept ILSpy-generated code, // mcs has some compiler bugs that cause it to not accept ILSpy-generated code,
// for example when there's unreachable code due to other compiler bugs in the first mcs run. // for example when there's unreachable code due to other compiler bugs in the first mcs run.
options &= ~CompilerOptions.UseMcs; options &= ~CompilerOptions.UseMcsMask;
options |= CompilerOptions.UseRoslynLatest; options |= CompilerOptions.UseRoslynLatest;
// Also, add an .exe.config so that we consistently use the .NET 4.x runtime. // Also, add an .exe.config so that we consistently use the .NET 4.x runtime.
File.WriteAllText(outputFile.PathToAssembly + ".config", @"<?xml version=""1.0"" encoding=""utf-8""?> File.WriteAllText(outputFile.PathToAssembly + ".config", @"<?xml version=""1.0"" encoding=""utf-8""?>

2
ICSharpCode.Decompiler.Tests/Helpers/Tester.VB.cs

@ -40,7 +40,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
var preprocessorSymbols = GetPreprocessorSymbols(flags).Select(symbol => new KeyValuePair<string, object>(symbol, 1)).ToList(); var preprocessorSymbols = GetPreprocessorSymbols(flags).Select(symbol => new KeyValuePair<string, object>(symbol, 1)).ToList();
if (!flags.HasFlag(CompilerOptions.UseMcs)) if ((flags & CompilerOptions.UseMcsMask) == 0)
{ {
CompilerResults results = new CompilerResults(new TempFileCollection()); CompilerResults results = new CompilerResults(new TempFileCollection());
results.PathToAssembly = outputFileName ?? Path.GetTempFileName(); results.PathToAssembly = outputFileName ?? Path.GetTempFileName();

29
ICSharpCode.Decompiler.Tests/Helpers/Tester.cs

@ -55,7 +55,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
Force32Bit = 0x4, Force32Bit = 0x4,
Library = 0x8, Library = 0x8,
UseRoslyn1_3_2 = 0x10, UseRoslyn1_3_2 = 0x10,
UseMcs = 0x20, UseMcs2_6_4 = 0x20,
ReferenceVisualBasic = 0x40, ReferenceVisualBasic = 0x40,
ReferenceCore = 0x80, ReferenceCore = 0x80,
GeneratePdb = 0x100, GeneratePdb = 0x100,
@ -63,6 +63,8 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
UseRoslyn2_10_0 = 0x400, UseRoslyn2_10_0 = 0x400,
UseRoslyn3_11_0 = 0x800, UseRoslyn3_11_0 = 0x800,
UseRoslynLatest = 0x1000, UseRoslynLatest = 0x1000,
UseMcs5_23 = 0x2000,
UseMcsMask = UseMcs2_6_4 | UseMcs5_23,
UseRoslynMask = UseRoslyn1_3_2 | UseRoslyn2_10_0 | UseRoslyn3_11_0 | UseRoslynLatest UseRoslynMask = UseRoslyn1_3_2 | UseRoslyn2_10_0 | UseRoslyn3_11_0 | UseRoslynLatest
} }
@ -335,9 +337,17 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
} }
} }
} }
else if (flags.HasFlag(CompilerOptions.UseMcs)) else if ((flags & CompilerOptions.UseMcsMask) != 0)
{ {
preprocessorSymbols.Add("MCS"); preprocessorSymbols.Add("MCS");
if (flags.HasFlag(CompilerOptions.UseMcs2_6_4))
{
preprocessorSymbols.Add("MCS2");
}
if (flags.HasFlag(CompilerOptions.UseMcs5_23))
{
preprocessorSymbols.Add("MCS5");
}
} }
else else
{ {
@ -361,7 +371,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
var preprocessorSymbols = GetPreprocessorSymbols(flags); var preprocessorSymbols = GetPreprocessorSymbols(flags);
if (!flags.HasFlag(CompilerOptions.UseMcs)) if ((flags & CompilerOptions.UseMcsMask) == 0)
{ {
CompilerResults results = new CompilerResults(new TempFileCollection()); CompilerResults results = new CompilerResults(new TempFileCollection());
results.PathToAssembly = outputFileName ?? Path.GetTempFileName(); results.PathToAssembly = outputFileName ?? Path.GetTempFileName();
@ -476,7 +486,10 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
Assert.Ignore($"Compilation with mcs ignored: test directory '{testBasePath}' needs to be checked out separately." + Environment.NewLine + Assert.Ignore($"Compilation with mcs ignored: test directory '{testBasePath}' needs to be checked out separately." + Environment.NewLine +
$"git clone https://github.com/icsharpcode/ILSpy-tests \"{testBasePath}\""); $"git clone https://github.com/icsharpcode/ILSpy-tests \"{testBasePath}\"");
} }
string mcsPath = Path.Combine(testBasePath, @"mcs\2.6.4\bin\gmcs.bat"); string mcsPath = (flags & CompilerOptions.UseMcsMask) switch {
CompilerOptions.UseMcs5_23 => Path.Combine(testBasePath, @"mcs\5.23\bin\mcs.bat"),
_ => Path.Combine(testBasePath, @"mcs\2.6.4\bin\gmcs.bat")
};
string otherOptions = " -unsafe -o" + (flags.HasFlag(CompilerOptions.Optimize) ? "+ " : "- "); string otherOptions = " -unsafe -o" + (flags.HasFlag(CompilerOptions.Optimize) ? "+ " : "- ");
if (flags.HasFlag(CompilerOptions.Library)) if (flags.HasFlag(CompilerOptions.Library))
@ -544,7 +557,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
else else
{ {
var settings = new DecompilerSettings(CSharp.LanguageVersion.CSharp5); var settings = new DecompilerSettings(CSharp.LanguageVersion.CSharp5);
if (cscOptions.HasFlag(CompilerOptions.UseMcs)) if ((cscOptions & CompilerOptions.UseMcsMask) != 0)
{ {
// we don't recompile with mcs but with roslyn, so we can use ref locals // we don't recompile with mcs but with roslyn, so we can use ref locals
settings.UseRefLocalsForAccurateOrderOfEvaluation = true; settings.UseRefLocalsForAccurateOrderOfEvaluation = true;
@ -609,8 +622,10 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
suffix += ".roslyn3"; suffix += ".roslyn3";
if ((cscOptions & CompilerOptions.UseRoslynLatest) != 0) if ((cscOptions & CompilerOptions.UseRoslynLatest) != 0)
suffix += ".roslyn"; suffix += ".roslyn";
if ((cscOptions & CompilerOptions.UseMcs) != 0) if ((cscOptions & CompilerOptions.UseMcs2_6_4) != 0)
suffix += ".mcs"; suffix += ".mcs2";
if ((cscOptions & CompilerOptions.UseMcs5_23) != 0)
suffix += ".mcs5";
return suffix; return suffix;
} }

6
ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs

@ -127,8 +127,10 @@ namespace ICSharpCode.Decompiler.Tests
CompilerOptions.Optimize | CompilerOptions.UseRoslyn3_11_0, CompilerOptions.Optimize | CompilerOptions.UseRoslyn3_11_0,
CompilerOptions.UseRoslynLatest, CompilerOptions.UseRoslynLatest,
CompilerOptions.Optimize | CompilerOptions.UseRoslynLatest, CompilerOptions.Optimize | CompilerOptions.UseRoslynLatest,
CompilerOptions.UseMcs, CompilerOptions.UseMcs2_6_4,
CompilerOptions.Optimize | CompilerOptions.UseMcs CompilerOptions.Optimize | CompilerOptions.UseMcs2_6_4,
CompilerOptions.UseMcs5_23,
CompilerOptions.Optimize | CompilerOptions.UseMcs5_23
}; };
[Test] [Test]

12
ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.cs

@ -507,7 +507,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
public void ForEachBreakWhenFound(string name, ref StringComparison output) public void ForEachBreakWhenFound(string name, ref StringComparison output)
{ {
#if MCS #if MCS2
foreach (int value in Enum.GetValues(typeof(StringComparison))) foreach (int value in Enum.GetValues(typeof(StringComparison)))
{ {
if (((StringComparison)value).ToString() == name) if (((StringComparison)value).ToString() == name)
@ -516,6 +516,16 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
break; break;
} }
} }
#elif MCS5
foreach (int value in Enum.GetValues(typeof(StringComparison)))
{
StringComparison stringComparison = (StringComparison)value;
if (stringComparison.ToString() == name)
{
output = (StringComparison)value;
break;
}
}
#else #else
foreach (StringComparison value in Enum.GetValues(typeof(StringComparison))) foreach (StringComparison value in Enum.GetValues(typeof(StringComparison)))
{ {

2
ICSharpCode.Decompiler/CSharp/Transforms/IntroduceUsingDeclarations.cs

@ -163,7 +163,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
{ {
foreach (var v in function.Variables) foreach (var v in function.Variables)
{ {
if (v.Kind != IL.VariableKind.Parameter) if (v.Kind != IL.VariableKind.Parameter && v.Name != null)
resolver = resolver.AddVariable(new DefaultVariable(v.Type, v.Name)); resolver = resolver.AddVariable(new DefaultVariable(v.Type, v.Name));
} }
} }

46
ICSharpCode.Decompiler/IL/ControlFlow/YieldReturnDecompiler.cs

@ -172,7 +172,11 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
newBody.SortBlocks(deleteUnreachableBlocks: true); newBody.SortBlocks(deleteUnreachableBlocks: true);
function.CheckInvariant(ILPhase.Normal); function.CheckInvariant(ILPhase.Normal);
if (!isCompiledWithMono) if (isCompiledWithMono)
{
CleanSkipFinallyBodies(function);
}
else
{ {
DecompileFinallyBlocks(); DecompileFinallyBlocks();
ReconstructTryFinallyBlocks(function); ReconstructTryFinallyBlocks(function);
@ -181,8 +185,6 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
context.Step("Translate fields to local accesses", function); context.Step("Translate fields to local accesses", function);
TranslateFieldsToLocalAccess(function, function, fieldToParameterMap, isCompiledWithMono); TranslateFieldsToLocalAccess(function, function, fieldToParameterMap, isCompiledWithMono);
CleanSkipFinallyBodies(function);
// On mono, we still need to remove traces of the state variable(s): // On mono, we still need to remove traces of the state variable(s):
if (isCompiledWithMono) if (isCompiledWithMono)
{ {
@ -1230,8 +1232,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
{ {
return; // only mono-compiled code uses skipFinallyBodies return; // only mono-compiled code uses skipFinallyBodies
} }
context.StepStartGroup("CleanSkipFinallyBodies", function); context.StepStartGroup("CleanFinallyBlocks", function);
Block entryPoint = AsyncAwaitDecompiler.GetBodyEntryPoint(function.Body as BlockContainer);
if (skipFinallyBodies.StoreInstructions.Count != 0 || skipFinallyBodies.AddressCount != 0) if (skipFinallyBodies.StoreInstructions.Count != 0 || skipFinallyBodies.AddressCount != 0)
{ {
// misdetected another variable as doFinallyBodies? // misdetected another variable as doFinallyBodies?
@ -1241,7 +1242,9 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
} }
foreach (var tryFinally in function.Descendants.OfType<TryFinally>()) foreach (var tryFinally in function.Descendants.OfType<TryFinally>())
{ {
entryPoint = AsyncAwaitDecompiler.GetBodyEntryPoint(tryFinally.FinallyBlock as BlockContainer); if (!(tryFinally.FinallyBlock is BlockContainer container))
continue;
Block entryPoint = AsyncAwaitDecompiler.GetBodyEntryPoint(container);
if (entryPoint?.Instructions[0] is IfInstruction ifInst) if (entryPoint?.Instructions[0] is IfInstruction ifInst)
{ {
if (ifInst.Condition.MatchLogicNot(out var logicNotArg) && logicNotArg.MatchLdLoc(skipFinallyBodies)) if (ifInst.Condition.MatchLogicNot(out var logicNotArg) && logicNotArg.MatchLdLoc(skipFinallyBodies))
@ -1250,10 +1253,41 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
// condition will always be true now that we're using 'yield' instructions // condition will always be true now that we're using 'yield' instructions
entryPoint.Instructions[0] = ifInst.TrueInst; entryPoint.Instructions[0] = ifInst.TrueInst;
entryPoint.Instructions.RemoveRange(1, entryPoint.Instructions.Count - 1); entryPoint.Instructions.RemoveRange(1, entryPoint.Instructions.Count - 1);
// find new entryPoint after the old one was modified
entryPoint = AsyncAwaitDecompiler.GetBodyEntryPoint(container);
} }
} }
if (entryPoint?.Instructions.Count == 2
&& IsCallToMonoFinallyMethod(entryPoint.Instructions[0] as Call, out var finallyMethod)
&& entryPoint.Instructions[1].MatchLeave((BlockContainer)tryFinally.FinallyBlock))
{
context.Step("Inline " + finallyMethod.FullName + " into finally", tryFinally);
var finallyFunction = CreateILAst((MethodDefinitionHandle)finallyMethod.MetadataToken, context);
tryFinally.FinallyBlock = finallyFunction.Body;
var variables = finallyFunction.Variables.ToArray();
finallyFunction.Variables.Clear();
function.Variables.AddRange(variables);
}
} }
context.StepEndGroup(keepIfEmpty: true); context.StepEndGroup(keepIfEmpty: true);
bool IsCallToMonoFinallyMethod(Call call, out IMethod finallyMethod)
{
finallyMethod = default;
if (call == null)
return false;
if (!(call.Arguments.Count == 1 && call.Arguments[0].MatchLdThis()))
return false;
if (!call.Method.Name.StartsWith("<>__Finally"))
return false;
ITypeDefinition declaringTypeDefinition = call.Method.DeclaringTypeDefinition;
if (declaringTypeDefinition.MetadataToken != this.enumeratorType)
return false;
if (declaringTypeDefinition.ParentModule.PEFile.Metadata != metadata)
return false;
finallyMethod = call.Method;
return !call.Method.MetadataToken.IsNil;
}
} }
} }
} }

2
ICSharpCode.Decompiler/IL/Transforms/SwitchOnStringTransform.cs

@ -715,8 +715,6 @@ namespace ICSharpCode.Decompiler.IL.Transforms
foreach (var section in sectionsWithoutLabels) foreach (var section in sectionsWithoutLabels)
{ {
if (!section.Body.Match(defaultSection.Body).Success)
return false;
defaultSection.Labels = defaultSection.Labels.UnionWith(section.Labels); defaultSection.Labels = defaultSection.Labels.UnionWith(section.Labels);
if (section.HasNullLabel) if (section.HasNullLabel)
defaultSection.HasNullLabel = true; defaultSection.HasNullLabel = true;

2
ILSpy-tests

@ -1 +1 @@
Subproject commit aa8f1197e6a513bcc10bcc38ec7d2143d27a2246 Subproject commit 6f8860e420b54bdfd726ec3c58a4d178416f9156
Loading…
Cancel
Save