From 1bf31f9086b9610dd194f4e2b507b3f8c7b93f1a Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Sat, 7 Jun 2014 23:30:24 +0200 Subject: [PATCH] YieldReturnDecompiler: in ConstructExceptionTable(), avoid ToEnclosingInterval() call and use the full StateRange instead. This is necessary because the state indices for a given try block are no longer contiguous in Roslyn-compiled code. Closes #468. --- ICSharpCode.Decompiler/ILAst/StateRange.cs | 8 ++++---- .../ILAst/YieldReturnDecompiler.cs | 18 +++++++++--------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/ICSharpCode.Decompiler/ILAst/StateRange.cs b/ICSharpCode.Decompiler/ILAst/StateRange.cs index 4a55e1d0b..d98bc4c2b 100644 --- a/ICSharpCode.Decompiler/ILAst/StateRange.cs +++ b/ICSharpCode.Decompiler/ILAst/StateRange.cs @@ -137,7 +137,7 @@ namespace ICSharpCode.Decompiler.ILAst internal DefaultDictionary ranges; SymbolicEvaluationContext evalContext; - internal Dictionary finallyMethodToStateInterval; // used only for IteratorDispose + internal Dictionary finallyMethodToStateRange; // used only for IteratorDispose /// /// Initializes the state range logic: @@ -148,7 +148,7 @@ namespace ICSharpCode.Decompiler.ILAst this.mode = mode; this.stateField = stateField; if (mode == StateRangeAnalysisMode.IteratorDispose) { - finallyMethodToStateInterval = new Dictionary(); + finallyMethodToStateRange = new Dictionary(); } ranges = new DefaultDictionary(n => new StateRange()); @@ -249,9 +249,9 @@ namespace ICSharpCode.Decompiler.ILAst // in some cases (e.g. foreach over array) the C# compiler produces a finally method outside of try-finally blocks if (mode == StateRangeAnalysisMode.IteratorDispose) { MethodDefinition mdef = (expr.Operand as MethodReference).ResolveWithinSameModule(); - if (mdef == null || finallyMethodToStateInterval.ContainsKey(mdef)) + if (mdef == null || finallyMethodToStateRange.ContainsKey(mdef)) throw new SymbolicAnalysisFailedException(); - finallyMethodToStateInterval.Add(mdef, nodeRange.ToEnclosingInterval()); + finallyMethodToStateRange.Add(mdef, nodeRange); break; } else { goto default; diff --git a/ICSharpCode.Decompiler/ILAst/YieldReturnDecompiler.cs b/ICSharpCode.Decompiler/ILAst/YieldReturnDecompiler.cs index b4b6183bf..a7a56f8fb 100644 --- a/ICSharpCode.Decompiler/ILAst/YieldReturnDecompiler.cs +++ b/ICSharpCode.Decompiler/ILAst/YieldReturnDecompiler.cs @@ -312,7 +312,7 @@ namespace ICSharpCode.Decompiler.ILAst // This is (int.MinValue, int.MaxValue) for the first instruction. // These ranges are propagated depending on the conditional jumps performed by the code. - Dictionary finallyMethodToStateInterval; + Dictionary finallyMethodToStateRange; void ConstructExceptionTable() { @@ -321,11 +321,11 @@ namespace ICSharpCode.Decompiler.ILAst var rangeAnalysis = new StateRangeAnalysis(ilMethod.Body[0], StateRangeAnalysisMode.IteratorDispose, stateField); rangeAnalysis.AssignStateRanges(ilMethod.Body, ilMethod.Body.Count); - finallyMethodToStateInterval = rangeAnalysis.finallyMethodToStateInterval; + finallyMethodToStateRange = rangeAnalysis.finallyMethodToStateRange; // Now look at the finally blocks: foreach (var tryFinally in ilMethod.GetSelfAndChildrenRecursive()) { - Interval interval = rangeAnalysis.ranges[tryFinally.TryBlock.Body[0]].ToEnclosingInterval(); + var range = rangeAnalysis.ranges[tryFinally.TryBlock.Body[0]]; var finallyBody = tryFinally.FinallyBlock.Body; if (finallyBody.Count != 2) throw new SymbolicAnalysisFailedException(); @@ -338,9 +338,9 @@ namespace ICSharpCode.Decompiler.ILAst throw new SymbolicAnalysisFailedException(); MethodDefinition mdef = GetMethodDefinition(call.Operand as MethodReference); - if (mdef == null || finallyMethodToStateInterval.ContainsKey(mdef)) + if (mdef == null || finallyMethodToStateRange.ContainsKey(mdef)) throw new SymbolicAnalysisFailedException(); - finallyMethodToStateInterval.Add(mdef, interval); + finallyMethodToStateRange.Add(mdef, range); } rangeAnalysis = null; } @@ -507,21 +507,21 @@ namespace ICSharpCode.Decompiler.ILAst MethodDefinition method = GetMethodDefinition(expr.Operand as MethodReference); if (method == null) throw new SymbolicAnalysisFailedException(); - Interval interval; + StateRange stateRange; if (method == disposeMethod) { // Explicit call to dispose is used for "yield break;" within the method. ILExpression br = body.ElementAtOrDefault(++pos) as ILExpression; if (br == null || !(br.Code == ILCode.Br || br.Code == ILCode.Leave) || br.Operand != returnFalseLabel) throw new SymbolicAnalysisFailedException(); newBody.Add(MakeGoTo(returnFalseLabel)); - } else if (finallyMethodToStateInterval.TryGetValue(method, out interval)) { + } else if (finallyMethodToStateRange.TryGetValue(method, out stateRange)) { // Call to Finally-method - int index = stateChanges.FindIndex(ss => ss.NewState >= interval.Start && ss.NewState <= interval.End); + int index = stateChanges.FindIndex(ss => stateRange.Contains(ss.NewState)); if (index < 0) throw new SymbolicAnalysisFailedException(); ILLabel label = new ILLabel(); - label.Name = "JumpOutOfTryFinally" + interval.Start + "_" + interval.End; + label.Name = "JumpOutOfTryFinally" + stateChanges[index].NewState; newBody.Add(new ILExpression(ILCode.Leave, label)); SetState stateChange = stateChanges[index];