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 @@ -75,8 +75,10 @@ namespace ICSharpCode.Decompiler.Tests
CompilerOptions.Optimize | CompilerOptions.UseRoslyn3_11_0,
CompilerOptions.UseRoslynLatest,
CompilerOptions.Optimize | CompilerOptions.UseRoslynLatest,
CompilerOptions.UseMcs,
CompilerOptions.Optimize | CompilerOptions.UseMcs
CompilerOptions.UseMcs2_6_4,
CompilerOptions.Optimize | CompilerOptions.UseMcs2_6_4,
CompilerOptions.UseMcs5_23,
CompilerOptions.Optimize | CompilerOptions.UseMcs5_23
};
static readonly CompilerOptions[] roslynOnlyOptions =
@ -286,7 +288,7 @@ namespace ICSharpCode.Decompiler.Tests @@ -286,7 +288,7 @@ namespace ICSharpCode.Decompiler.Tests
[Test]
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!");
}
@ -314,7 +316,7 @@ namespace ICSharpCode.Decompiler.Tests @@ -314,7 +316,7 @@ namespace ICSharpCode.Decompiler.Tests
[Test]
public void YieldReturn([ValueSource(nameof(defaultOptions))] CompilerOptions options)
{
if (options.HasFlag(CompilerOptions.UseMcs))
if ((options & CompilerOptions.UseMcsMask) != 0)
{
Assert.Ignore("Decompiler bug with mono!");
}
@ -348,7 +350,7 @@ namespace ICSharpCode.Decompiler.Tests @@ -348,7 +350,7 @@ namespace ICSharpCode.Decompiler.Tests
[Test]
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!");
}
@ -366,12 +368,12 @@ namespace ICSharpCode.Decompiler.Tests @@ -366,12 +368,12 @@ namespace ICSharpCode.Decompiler.Tests
outputFile = Tester.CompileCSharp(Path.Combine(TestCasePath, testFileName), options,
outputFileName: Path.Combine(TestCasePath, testOutputFileName));
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.
// 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.
options &= ~CompilerOptions.UseMcs;
options &= ~CompilerOptions.UseMcsMask;
options |= CompilerOptions.UseRoslynLatest;
// 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""?>

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

@ -40,7 +40,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -40,7 +40,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
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());
results.PathToAssembly = outputFileName ?? Path.GetTempFileName();

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

@ -55,7 +55,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -55,7 +55,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
Force32Bit = 0x4,
Library = 0x8,
UseRoslyn1_3_2 = 0x10,
UseMcs = 0x20,
UseMcs2_6_4 = 0x20,
ReferenceVisualBasic = 0x40,
ReferenceCore = 0x80,
GeneratePdb = 0x100,
@ -63,6 +63,8 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -63,6 +63,8 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
UseRoslyn2_10_0 = 0x400,
UseRoslyn3_11_0 = 0x800,
UseRoslynLatest = 0x1000,
UseMcs5_23 = 0x2000,
UseMcsMask = UseMcs2_6_4 | UseMcs5_23,
UseRoslynMask = UseRoslyn1_3_2 | UseRoslyn2_10_0 | UseRoslyn3_11_0 | UseRoslynLatest
}
@ -335,9 +337,17 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -335,9 +337,17 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
}
}
}
else if (flags.HasFlag(CompilerOptions.UseMcs))
else if ((flags & CompilerOptions.UseMcsMask) != 0)
{
preprocessorSymbols.Add("MCS");
if (flags.HasFlag(CompilerOptions.UseMcs2_6_4))
{
preprocessorSymbols.Add("MCS2");
}
if (flags.HasFlag(CompilerOptions.UseMcs5_23))
{
preprocessorSymbols.Add("MCS5");
}
}
else
{
@ -361,7 +371,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -361,7 +371,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
var preprocessorSymbols = GetPreprocessorSymbols(flags);
if (!flags.HasFlag(CompilerOptions.UseMcs))
if ((flags & CompilerOptions.UseMcsMask) == 0)
{
CompilerResults results = new CompilerResults(new TempFileCollection());
results.PathToAssembly = outputFileName ?? Path.GetTempFileName();
@ -476,7 +486,10 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -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 +
$"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) ? "+ " : "- ");
if (flags.HasFlag(CompilerOptions.Library))
@ -544,7 +557,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -544,7 +557,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
else
{
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
settings.UseRefLocalsForAccurateOrderOfEvaluation = true;
@ -609,8 +622,10 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -609,8 +622,10 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
suffix += ".roslyn3";
if ((cscOptions & CompilerOptions.UseRoslynLatest) != 0)
suffix += ".roslyn";
if ((cscOptions & CompilerOptions.UseMcs) != 0)
suffix += ".mcs";
if ((cscOptions & CompilerOptions.UseMcs2_6_4) != 0)
suffix += ".mcs2";
if ((cscOptions & CompilerOptions.UseMcs5_23) != 0)
suffix += ".mcs5";
return suffix;
}

6
ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs

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

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

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

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

@ -163,7 +163,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -163,7 +163,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
{
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));
}
}

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

@ -172,7 +172,11 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -172,7 +172,11 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
newBody.SortBlocks(deleteUnreachableBlocks: true);
function.CheckInvariant(ILPhase.Normal);
if (!isCompiledWithMono)
if (isCompiledWithMono)
{
CleanSkipFinallyBodies(function);
}
else
{
DecompileFinallyBlocks();
ReconstructTryFinallyBlocks(function);
@ -181,8 +185,6 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -181,8 +185,6 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
context.Step("Translate fields to local accesses", function);
TranslateFieldsToLocalAccess(function, function, fieldToParameterMap, isCompiledWithMono);
CleanSkipFinallyBodies(function);
// On mono, we still need to remove traces of the state variable(s):
if (isCompiledWithMono)
{
@ -1230,8 +1232,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -1230,8 +1232,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
{
return; // only mono-compiled code uses skipFinallyBodies
}
context.StepStartGroup("CleanSkipFinallyBodies", function);
Block entryPoint = AsyncAwaitDecompiler.GetBodyEntryPoint(function.Body as BlockContainer);
context.StepStartGroup("CleanFinallyBlocks", function);
if (skipFinallyBodies.StoreInstructions.Count != 0 || skipFinallyBodies.AddressCount != 0)
{
// misdetected another variable as doFinallyBodies?
@ -1241,7 +1242,9 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -1241,7 +1242,9 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
}
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 (ifInst.Condition.MatchLogicNot(out var logicNotArg) && logicNotArg.MatchLdLoc(skipFinallyBodies))
@ -1250,10 +1253,41 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -1250,10 +1253,41 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
// condition will always be true now that we're using 'yield' instructions
entryPoint.Instructions[0] = ifInst.TrueInst;
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);
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 @@ -715,8 +715,6 @@ namespace ICSharpCode.Decompiler.IL.Transforms
foreach (var section in sectionsWithoutLabels)
{
if (!section.Body.Match(defaultSection.Body).Success)
return false;
defaultSection.Labels = defaultSection.Labels.UnionWith(section.Labels);
if (section.HasNullLabel)
defaultSection.HasNullLabel = true;

2
ILSpy-tests

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