~ubuntu-branches/ubuntu/trusty/monodevelop/trusty-proposed

« back to all changes in this revision

Viewing changes to contrib/ICSharpCode.Decompiler/ILAst/YieldReturnDecompiler.cs

  • Committer: Package Import Robot
  • Author(s): Jo Shields
  • Date: 2013-05-12 09:46:03 UTC
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20130512094603-mad323bzcxvmcam0
Tags: upstream-4.0.5+dfsg
ImportĀ upstreamĀ versionĀ 4.0.5+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
24
24
 
25
25
namespace ICSharpCode.Decompiler.ILAst
26
26
{
27
 
        public class YieldReturnDecompiler
 
27
        class YieldReturnDecompiler
28
28
        {
29
29
                // For a description on the code generated by the C# compiler for yield return:
30
30
                // http://csharpindepth.com/Articles/Chapter6/IteratorBlockImplementation.aspx
34
34
                // - Figure out which of the fields is the state field
35
35
                // - Construct an exception table based on states. This allows us to determine, for each state, what the parent try block is.
36
36
                
37
 
                /// <summary>
38
 
                /// This exception is thrown when we find something else than we expect from the C# compiler.
39
 
                /// This aborts the analysis and makes the whole transform fail.
40
 
                /// </summary>
41
 
                class YieldAnalysisFailedException : Exception {}
 
37
                // See http://community.sharpdevelop.net/blogs/danielgrunwald/archive/2011/03/06/ilspy-yield-return.aspx
 
38
                // for a description of this step.
42
39
                
43
40
                DecompilerContext context;
44
41
                TypeDefinition enumeratorType;
66
63
                                #endif
67
64
                                try {
68
65
                                        yrd.Run();
69
 
                                } catch (YieldAnalysisFailedException) {
 
66
                                } catch (SymbolicAnalysisFailedException) {
70
67
                                        return;
71
68
                                }
72
69
                                #if DEBUG
211
208
                                }
212
209
                        }
213
210
                        if (stateField == null)
214
 
                                throw new YieldAnalysisFailedException();
 
211
                                throw new SymbolicAnalysisFailedException();
215
212
                }
216
213
                
217
214
                /// <summary>
220
217
                ILBlock CreateILAst(MethodDefinition method)
221
218
                {
222
219
                        if (method == null || !method.HasBody)
223
 
                                throw new YieldAnalysisFailedException();
 
220
                                throw new SymbolicAnalysisFailedException();
224
221
                        
225
222
                        ILBlock ilMethod = new ILBlock();
226
223
                        ILAstBuilder astBuilder = new ILAstBuilder();
269
266
                                }
270
267
                        }
271
268
                        if (currentField == null)
272
 
                                throw new YieldAnalysisFailedException();
 
269
                                throw new SymbolicAnalysisFailedException();
273
270
                }
274
271
                #endregion
275
272
                
322
319
                        disposeMethod = enumeratorType.Methods.FirstOrDefault(m => m.Name == "System.IDisposable.Dispose");
323
320
                        ILBlock ilMethod = CreateILAst(disposeMethod);
324
321
                        
325
 
                        finallyMethodToStateInterval = new Dictionary<MethodDefinition, Interval>();
326
 
                        
327
 
                        InitStateRanges(ilMethod.Body[0]);
328
 
                        AssignStateRanges(ilMethod.Body, ilMethod.Body.Count, forDispose: true);
 
322
                        var rangeAnalysis = new StateRangeAnalysis(ilMethod.Body[0], StateRangeAnalysisMode.IteratorDispose, stateField);
 
323
                        rangeAnalysis.AssignStateRanges(ilMethod.Body, ilMethod.Body.Count);
 
324
                        finallyMethodToStateInterval = rangeAnalysis.finallyMethodToStateInterval;
329
325
                        
330
326
                        // Now look at the finally blocks:
331
327
                        foreach (var tryFinally in ilMethod.GetSelfAndChildrenRecursive<ILTryCatchBlock>()) {
332
 
                                Interval interval = ranges[tryFinally.TryBlock.Body[0]].ToEnclosingInterval();
 
328
                                Interval interval = rangeAnalysis.ranges[tryFinally.TryBlock.Body[0]].ToEnclosingInterval();
333
329
                                var finallyBody = tryFinally.FinallyBlock.Body;
334
330
                                if (finallyBody.Count != 2)
335
 
                                        throw new YieldAnalysisFailedException();
 
331
                                        throw new SymbolicAnalysisFailedException();
336
332
                                ILExpression call = finallyBody[0] as ILExpression;
337
333
                                if (call == null || call.Code != ILCode.Call || call.Arguments.Count != 1)
338
 
                                        throw new YieldAnalysisFailedException();
 
334
                                        throw new SymbolicAnalysisFailedException();
339
335
                                if (!call.Arguments[0].MatchThis())
340
 
                                        throw new YieldAnalysisFailedException();
 
336
                                        throw new SymbolicAnalysisFailedException();
341
337
                                if (!finallyBody[1].Match(ILCode.Endfinally))
342
 
                                        throw new YieldAnalysisFailedException();
 
338
                                        throw new SymbolicAnalysisFailedException();
343
339
                                
344
340
                                MethodDefinition mdef = GetMethodDefinition(call.Operand as MethodReference);
345
341
                                if (mdef == null || finallyMethodToStateInterval.ContainsKey(mdef))
346
 
                                        throw new YieldAnalysisFailedException();
 
342
                                        throw new SymbolicAnalysisFailedException();
347
343
                                finallyMethodToStateInterval.Add(mdef, interval);
348
344
                        }
349
 
                        ranges = null;
350
 
                }
351
 
                #endregion
352
 
                
353
 
                #region Assign StateRanges / Symbolic Execution (used for analysis of Dispose() and MoveNext())
354
 
                #region struct Interval / class StateRange
355
 
                struct Interval
356
 
                {
357
 
                        public readonly int Start, End;
358
 
                        
359
 
                        public Interval(int start, int end)
360
 
                        {
361
 
                                Debug.Assert(start <= end || (start == 0 && end == -1));
362
 
                                this.Start = start;
363
 
                                this.End = end;
364
 
                        }
365
 
                        
366
 
                        public override string ToString()
367
 
                        {
368
 
                                return string.Format("({0} to {1})", Start, End);
369
 
                        }
370
 
                }
371
 
                
372
 
                class StateRange
373
 
                {
374
 
                        readonly List<Interval> data = new List<Interval>();
375
 
                        
376
 
                        public StateRange()
377
 
                        {
378
 
                        }
379
 
                        
380
 
                        public StateRange(int start, int end)
381
 
                        {
382
 
                                this.data.Add(new Interval(start, end));
383
 
                        }
384
 
                        
385
 
                        public bool Contains(int val)
386
 
                        {
387
 
                                foreach (Interval v in data) {
388
 
                                        if (v.Start <= val && val <= v.End)
389
 
                                                return true;
390
 
                                }
391
 
                                return false;
392
 
                        }
393
 
                        
394
 
                        public void UnionWith(StateRange other)
395
 
                        {
396
 
                                data.AddRange(other.data);
397
 
                        }
398
 
                        
399
 
                        /// <summary>
400
 
                        /// Unions this state range with (other intersect (minVal to maxVal))
401
 
                        /// </summary>
402
 
                        public void UnionWith(StateRange other, int minVal, int maxVal)
403
 
                        {
404
 
                                foreach (Interval v in other.data) {
405
 
                                        int start = Math.Max(v.Start, minVal);
406
 
                                        int end = Math.Min(v.End, maxVal);
407
 
                                        if (start <= end)
408
 
                                                data.Add(new Interval(start, end));
409
 
                                }
410
 
                        }
411
 
                        
412
 
                        /// <summary>
413
 
                        /// Merges overlapping interval ranges.
414
 
                        /// </summary>
415
 
                        public void Simplify()
416
 
                        {
417
 
                                if (data.Count < 2)
418
 
                                        return;
419
 
                                data.Sort((a, b) => a.Start.CompareTo(b.Start));
420
 
                                Interval prev = data[0];
421
 
                                int prevIndex = 0;
422
 
                                for (int i = 1; i < data.Count; i++) {
423
 
                                        Interval next = data[i];
424
 
                                        Debug.Assert(prev.Start <= next.Start);
425
 
                                        if (next.Start <= prev.End + 1) { // intervals overlapping or touching
426
 
                                                prev = new Interval(prev.Start, Math.Max(prev.End, next.End));
427
 
                                                data[prevIndex] = prev;
428
 
                                                data[i] = new Interval(0, -1); // mark as deleted
429
 
                                        } else {
430
 
                                                prev = next;
431
 
                                                prevIndex = i;
432
 
                                        }
433
 
                                }
434
 
                                data.RemoveAll(i => i.Start > i.End); // remove all entries that were marked as deleted
435
 
                        }
436
 
                        
437
 
                        public override string ToString()
438
 
                        {
439
 
                                return string.Join(",", data);
440
 
                        }
441
 
                        
442
 
                        public Interval ToEnclosingInterval()
443
 
                        {
444
 
                                if (data.Count == 0)
445
 
                                        throw new YieldAnalysisFailedException();
446
 
                                return new Interval(data[0].Start, data[data.Count - 1].End);
447
 
                        }
448
 
                }
449
 
                #endregion
450
 
                
451
 
                DefaultDictionary<ILNode, StateRange> ranges;
452
 
                ILVariable rangeAnalysisStateVariable;
453
 
                
454
 
                /// <summary>
455
 
                /// Initializes the state range logic:
456
 
                /// Clears 'ranges' and sets 'ranges[entryPoint]' to the full range (int.MinValue to int.MaxValue)
457
 
                /// </summary>
458
 
                void InitStateRanges(ILNode entryPoint)
459
 
                {
460
 
                        ranges = new DefaultDictionary<ILNode, StateRange>(n => new StateRange());
461
 
                        ranges[entryPoint] = new StateRange(int.MinValue, int.MaxValue);
462
 
                        rangeAnalysisStateVariable = null;
463
 
                }
464
 
                
465
 
                int AssignStateRanges(List<ILNode> body, int bodyLength, bool forDispose)
466
 
                {
467
 
                        if (bodyLength == 0)
468
 
                                return 0;
469
 
                        for (int i = 0; i < bodyLength; i++) {
470
 
                                StateRange nodeRange = ranges[body[i]];
471
 
                                nodeRange.Simplify();
472
 
                                
473
 
                                ILLabel label = body[i] as ILLabel;
474
 
                                if (label != null) {
475
 
                                        ranges[body[i + 1]].UnionWith(nodeRange);
476
 
                                        continue;
477
 
                                }
478
 
                                
479
 
                                ILTryCatchBlock tryFinally = body[i] as ILTryCatchBlock;
480
 
                                if (tryFinally != null) {
481
 
                                        if (!forDispose || tryFinally.CatchBlocks.Count != 0 || tryFinally.FaultBlock != null || tryFinally.FinallyBlock == null)
482
 
                                                throw new YieldAnalysisFailedException();
483
 
                                        ranges[tryFinally.TryBlock].UnionWith(nodeRange);
484
 
                                        if (tryFinally.TryBlock.Body.Count != 0) {
485
 
                                                ranges[tryFinally.TryBlock.Body[0]].UnionWith(nodeRange);
486
 
                                                AssignStateRanges(tryFinally.TryBlock.Body, tryFinally.TryBlock.Body.Count, forDispose);
487
 
                                        }
488
 
                                        continue;
489
 
                                }
490
 
                                
491
 
                                ILExpression expr = body[i] as ILExpression;
492
 
                                if (expr == null)
493
 
                                        throw new YieldAnalysisFailedException();
494
 
                                switch (expr.Code) {
495
 
                                        case ILCode.Switch:
496
 
                                                {
497
 
                                                        SymbolicValue val = Eval(expr.Arguments[0]);
498
 
                                                        if (val.Type != SymbolicValueType.State)
499
 
                                                                throw new YieldAnalysisFailedException();
500
 
                                                        ILLabel[] targetLabels = (ILLabel[])expr.Operand;
501
 
                                                        for (int j = 0; j < targetLabels.Length; j++) {
502
 
                                                                int state = j - val.Constant;
503
 
                                                                ranges[targetLabels[j]].UnionWith(nodeRange, state, state);
504
 
                                                        }
505
 
                                                        StateRange nextRange = ranges[body[i + 1]];
506
 
                                                        nextRange.UnionWith(nodeRange, int.MinValue, -1 - val.Constant);
507
 
                                                        nextRange.UnionWith(nodeRange, targetLabels.Length - val.Constant, int.MaxValue);
508
 
                                                        break;
509
 
                                                }
510
 
                                        case ILCode.Br:
511
 
                                        case ILCode.Leave:
512
 
                                                ranges[(ILLabel)expr.Operand].UnionWith(nodeRange);
513
 
                                                break;
514
 
                                        case ILCode.Brtrue:
515
 
                                                {
516
 
                                                        SymbolicValue val = Eval(expr.Arguments[0]);
517
 
                                                        if (val.Type == SymbolicValueType.StateEquals) {
518
 
                                                                ranges[(ILLabel)expr.Operand].UnionWith(nodeRange, val.Constant, val.Constant);
519
 
                                                                StateRange nextRange = ranges[body[i + 1]];
520
 
                                                                nextRange.UnionWith(nodeRange, int.MinValue, val.Constant - 1);
521
 
                                                                nextRange.UnionWith(nodeRange, val.Constant + 1, int.MaxValue);
522
 
                                                        } else if (val.Type == SymbolicValueType.StateInEquals) {
523
 
                                                                ranges[body[i + 1]].UnionWith(nodeRange, val.Constant, val.Constant);
524
 
                                                                StateRange targetRange = ranges[(ILLabel)expr.Operand];
525
 
                                                                targetRange.UnionWith(nodeRange, int.MinValue, val.Constant - 1);
526
 
                                                                targetRange.UnionWith(nodeRange, val.Constant + 1, int.MaxValue);
527
 
                                                        } else {
528
 
                                                                throw new YieldAnalysisFailedException();
529
 
                                                        }
530
 
                                                        break;
531
 
                                                }
532
 
                                        case ILCode.Nop:
533
 
                                                ranges[body[i + 1]].UnionWith(nodeRange);
534
 
                                                break;
535
 
                                        case ILCode.Ret:
536
 
                                                break;
537
 
                                        case ILCode.Stloc:
538
 
                                                {
539
 
                                                        SymbolicValue val = Eval(expr.Arguments[0]);
540
 
                                                        if (val.Type == SymbolicValueType.State && val.Constant == 0 && rangeAnalysisStateVariable == null)
541
 
                                                                rangeAnalysisStateVariable = (ILVariable)expr.Operand;
542
 
                                                        else
543
 
                                                                throw new YieldAnalysisFailedException();
544
 
                                                        goto case ILCode.Nop;
545
 
                                                }
546
 
                                        case ILCode.Call:
547
 
                                                // in some cases (e.g. foreach over array) the C# compiler produces a finally method outside of try-finally blocks
548
 
                                                if (forDispose) {
549
 
                                                        MethodDefinition mdef = GetMethodDefinition(expr.Operand as MethodReference);
550
 
                                                        if (mdef == null || finallyMethodToStateInterval.ContainsKey(mdef))
551
 
                                                                throw new YieldAnalysisFailedException();
552
 
                                                        finallyMethodToStateInterval.Add(mdef, nodeRange.ToEnclosingInterval());
553
 
                                                } else {
554
 
                                                        throw new YieldAnalysisFailedException();
555
 
                                                }
556
 
                                                break;
557
 
                                        default:
558
 
                                                if (forDispose)
559
 
                                                        throw new YieldAnalysisFailedException();
560
 
                                                else
561
 
                                                        return i;
562
 
                                }
563
 
                        }
564
 
                        return bodyLength;
565
 
                }
566
 
                
567
 
                enum SymbolicValueType
568
 
                {
569
 
                        /// <summary>
570
 
                        /// int: Constant (result of ldc.i4)
571
 
                        /// </summary>
572
 
                        IntegerConstant,
573
 
                        /// <summary>
574
 
                        /// int: State + Constant
575
 
                        /// </summary>
576
 
                        State,
577
 
                        /// <summary>
578
 
                        /// This pointer (result of ldarg.0)
579
 
                        /// </summary>
580
 
                        This,
581
 
                        /// <summary>
582
 
                        /// bool: State == Constant
583
 
                        /// </summary>
584
 
                        StateEquals,
585
 
                        /// <summary>
586
 
                        /// bool: State != Constant
587
 
                        /// </summary>
588
 
                        StateInEquals
589
 
                }
590
 
                
591
 
                struct SymbolicValue
592
 
                {
593
 
                        public readonly int Constant;
594
 
                        public readonly SymbolicValueType Type;
595
 
                        
596
 
                        public SymbolicValue(SymbolicValueType type, int constant = 0)
597
 
                        {
598
 
                                this.Type = type;
599
 
                                this.Constant = constant;
600
 
                        }
601
 
                        
602
 
                        public override string ToString()
603
 
                        {
604
 
                                return string.Format("[SymbolicValue {0}: {1}]", this.Type, this.Constant);
605
 
                        }
606
 
                }
607
 
                
608
 
                SymbolicValue Eval(ILExpression expr)
609
 
                {
610
 
                        SymbolicValue left, right;
611
 
                        switch (expr.Code) {
612
 
                                case ILCode.Sub:
613
 
                                        left = Eval(expr.Arguments[0]);
614
 
                                        right = Eval(expr.Arguments[1]);
615
 
                                        if (left.Type != SymbolicValueType.State && left.Type != SymbolicValueType.IntegerConstant)
616
 
                                                throw new YieldAnalysisFailedException();
617
 
                                        if (right.Type != SymbolicValueType.IntegerConstant)
618
 
                                                throw new YieldAnalysisFailedException();
619
 
                                        return new SymbolicValue(left.Type, unchecked ( left.Constant - right.Constant ));
620
 
                                case ILCode.Ldfld:
621
 
                                        if (Eval(expr.Arguments[0]).Type != SymbolicValueType.This)
622
 
                                                throw new YieldAnalysisFailedException();
623
 
                                        if (GetFieldDefinition(expr.Operand as FieldReference) != stateField)
624
 
                                                throw new YieldAnalysisFailedException();
625
 
                                        return new SymbolicValue(SymbolicValueType.State);
626
 
                                case ILCode.Ldloc:
627
 
                                        ILVariable loadedVariable = (ILVariable)expr.Operand;
628
 
                                        if (loadedVariable == rangeAnalysisStateVariable)
629
 
                                                return new SymbolicValue(SymbolicValueType.State);
630
 
                                        else if (loadedVariable.IsParameter && loadedVariable.OriginalParameter.Index < 0)
631
 
                                                return new SymbolicValue(SymbolicValueType.This);
632
 
                                        else
633
 
                                                throw new YieldAnalysisFailedException();
634
 
                                case ILCode.Ldc_I4:
635
 
                                        return new SymbolicValue(SymbolicValueType.IntegerConstant, (int)expr.Operand);
636
 
                                case ILCode.Ceq:
637
 
                                case ILCode.Cne:
638
 
                                        left = Eval(expr.Arguments[0]);
639
 
                                        right = Eval(expr.Arguments[1]);
640
 
                                        if (left.Type != SymbolicValueType.State || right.Type != SymbolicValueType.IntegerConstant)
641
 
                                                throw new YieldAnalysisFailedException();
642
 
                                        // bool: (state + left.Constant == right.Constant)
643
 
                                        // bool: (state == right.Constant - left.Constant)
644
 
                                        return new SymbolicValue(expr.Code == ILCode.Ceq ? SymbolicValueType.StateEquals : SymbolicValueType.StateInEquals, unchecked(right.Constant - left.Constant));
645
 
                                case ILCode.LogicNot:
646
 
                                        SymbolicValue val = Eval(expr.Arguments[0]);
647
 
                                        if (val.Type == SymbolicValueType.StateEquals)
648
 
                                                return new SymbolicValue(SymbolicValueType.StateInEquals, val.Constant);
649
 
                                        else if (val.Type == SymbolicValueType.StateInEquals)
650
 
                                                return new SymbolicValue(SymbolicValueType.StateEquals, val.Constant);
651
 
                                        else
652
 
                                                throw new YieldAnalysisFailedException();
653
 
                                default:
654
 
                                        throw new YieldAnalysisFailedException();
655
 
                        }
 
345
                        rangeAnalysis = null;
656
346
                }
657
347
                #endregion
658
348
                
667
357
                        ILBlock ilMethod = CreateILAst(moveNextMethod);
668
358
                        
669
359
                        if (ilMethod.Body.Count == 0)
670
 
                                throw new YieldAnalysisFailedException();
 
360
                                throw new SymbolicAnalysisFailedException();
671
361
                        ILExpression lastReturnArg;
672
362
                        if (!ilMethod.Body.Last().Match(ILCode.Ret, out lastReturnArg))
673
 
                                throw new YieldAnalysisFailedException();
 
363
                                throw new SymbolicAnalysisFailedException();
674
364
                        
675
365
                        // There are two possibilities:
676
366
                        if (lastReturnArg.Code == ILCode.Ldloc) {
678
368
                                returnVariable = (ILVariable)lastReturnArg.Operand;
679
369
                                returnLabel = ilMethod.Body.ElementAtOrDefault(ilMethod.Body.Count - 2) as ILLabel;
680
370
                                if (returnLabel == null)
681
 
                                        throw new YieldAnalysisFailedException();
 
371
                                        throw new SymbolicAnalysisFailedException();
682
372
                        } else {
683
373
                                // b) the compiler directly returns constants
684
374
                                returnVariable = null;
685
375
                                returnLabel = null;
686
376
                                // In this case, the last return must return false.
687
377
                                if (lastReturnArg.Code != ILCode.Ldc_I4 || (int)lastReturnArg.Operand != 0)
688
 
                                        throw new YieldAnalysisFailedException();
 
378
                                        throw new SymbolicAnalysisFailedException();
689
379
                        }
690
380
                        
691
381
                        ILTryCatchBlock tryFaultBlock = ilMethod.Body[0] as ILTryCatchBlock;
694
384
                        if (tryFaultBlock != null) {
695
385
                                // there are try-finally blocks
696
386
                                if (returnVariable == null) // in this case, we must use a return variable
697
 
                                        throw new YieldAnalysisFailedException();
 
387
                                        throw new SymbolicAnalysisFailedException();
698
388
                                // must be a try-fault block:
699
389
                                if (tryFaultBlock.CatchBlocks.Count != 0 || tryFaultBlock.FinallyBlock != null || tryFaultBlock.FaultBlock == null)
700
 
                                        throw new YieldAnalysisFailedException();
 
390
                                        throw new SymbolicAnalysisFailedException();
701
391
                                
702
392
                                ILBlock faultBlock = tryFaultBlock.FaultBlock;
703
393
                                // Ensure the fault block contains the call to Dispose().
704
394
                                if (faultBlock.Body.Count != 2)
705
 
                                        throw new YieldAnalysisFailedException();
 
395
                                        throw new SymbolicAnalysisFailedException();
706
396
                                MethodReference disposeMethodRef;
707
397
                                ILExpression disposeArg;
708
398
                                if (!faultBlock.Body[0].Match(ILCode.Call, out disposeMethodRef, out disposeArg))
709
 
                                        throw new YieldAnalysisFailedException();
 
399
                                        throw new SymbolicAnalysisFailedException();
710
400
                                if (GetMethodDefinition(disposeMethodRef) != disposeMethod || !disposeArg.MatchThis())
711
 
                                        throw new YieldAnalysisFailedException();
 
401
                                        throw new SymbolicAnalysisFailedException();
712
402
                                if (!faultBlock.Body[1].Match(ILCode.Endfinally))
713
 
                                        throw new YieldAnalysisFailedException();
 
403
                                        throw new SymbolicAnalysisFailedException();
714
404
                                
715
405
                                body = tryFaultBlock.TryBlock.Body;
716
406
                                bodyLength = body.Count;
734
424
                                        bodyLength--;
735
425
                                ILExpression store0 = body.ElementAtOrDefault(bodyLength - 1) as ILExpression;
736
426
                                if (store0 == null || store0.Code != ILCode.Stloc || store0.Operand != returnVariable)
737
 
                                        throw new YieldAnalysisFailedException();
 
427
                                        throw new SymbolicAnalysisFailedException();
738
428
                                if (store0.Arguments[0].Code != ILCode.Ldc_I4 || (int)store0.Arguments[0].Operand != 0)
739
 
                                        throw new YieldAnalysisFailedException();
 
429
                                        throw new SymbolicAnalysisFailedException();
740
430
                                
741
431
                                bodyLength--; // don't conside the stloc instruction to be part of the body
742
432
                        }
743
433
                        // verify that the last element in the body is a label pointing to the 'ret(false)'
744
434
                        returnFalseLabel = body.ElementAtOrDefault(bodyLength - 1) as ILLabel;
745
435
                        if (returnFalseLabel == null)
746
 
                                throw new YieldAnalysisFailedException();
747
 
                        
748
 
                        InitStateRanges(body[0]);
749
 
                        int pos = AssignStateRanges(body, bodyLength, forDispose: false);
750
 
                        if (pos > 0 && body[pos - 1] is ILLabel) {
751
 
                                pos--;
752
 
                        } else {
753
 
                                // ensure that the first element at body[pos] is a label:
754
 
                                ILLabel newLabel = new ILLabel();
755
 
                                newLabel.Name = "YieldReturnEntryPoint";
756
 
                                ranges[newLabel] = ranges[body[pos]]; // give the label the range of the instruction at body[pos]
757
 
                                
758
 
                                body.Insert(pos, newLabel);
759
 
                                bodyLength++;
760
 
                        }
761
 
                        
762
 
                        List<KeyValuePair<ILLabel, StateRange>> labels = new List<KeyValuePair<ILLabel, StateRange>>();
763
 
                        for (int i = pos; i < bodyLength; i++) {
764
 
                                ILLabel label = body[i] as ILLabel;
765
 
                                if (label != null) {
766
 
                                        labels.Add(new KeyValuePair<ILLabel, StateRange>(label, ranges[label]));
767
 
                                }
768
 
                        }
769
 
                        
 
436
                                throw new SymbolicAnalysisFailedException();
 
437
                        
 
438
                        var rangeAnalysis = new StateRangeAnalysis(body[0], StateRangeAnalysisMode.IteratorMoveNext, stateField);
 
439
                        int pos = rangeAnalysis.AssignStateRanges(body, bodyLength);
 
440
                        rangeAnalysis.EnsureLabelAtPos(body, ref pos, ref bodyLength);
 
441
                        
 
442
                        var labels = rangeAnalysis.CreateLabelRangeMapping(body, pos, bodyLength);
770
443
                        ConvertBody(body, pos, bodyLength, labels);
771
444
                }
772
445
                #endregion
797
470
                                        // Handle stores to 'state' or 'current'
798
471
                                        if (GetFieldDefinition(expr.Operand as FieldReference) == stateField) {
799
472
                                                if (expr.Arguments[1].Code != ILCode.Ldc_I4)
800
 
                                                        throw new YieldAnalysisFailedException();
 
473
                                                        throw new SymbolicAnalysisFailedException();
801
474
                                                currentState = (int)expr.Arguments[1].Operand;
802
475
                                                stateChanges.Add(new SetState(newBody.Count, currentState));
803
476
                                        } else if (GetFieldDefinition(expr.Operand as FieldReference) == currentField) {
809
482
                                        // handle store+branch to the returnVariable
810
483
                                        ILExpression br = body.ElementAtOrDefault(++pos) as ILExpression;
811
484
                                        if (br == null || !(br.Code == ILCode.Br || br.Code == ILCode.Leave) || br.Operand != returnLabel || expr.Arguments[0].Code != ILCode.Ldc_I4)
812
 
                                                throw new YieldAnalysisFailedException();
 
485
                                                throw new SymbolicAnalysisFailedException();
813
486
                                        int val = (int)expr.Arguments[0].Operand;
814
487
                                        if (val == 0) {
815
488
                                                newBody.Add(MakeGoTo(returnFalseLabel));
816
489
                                        } else if (val == 1) {
817
490
                                                newBody.Add(MakeGoTo(labels, currentState));
818
491
                                        } else {
819
 
                                                throw new YieldAnalysisFailedException();
 
492
                                                throw new SymbolicAnalysisFailedException();
820
493
                                        }
821
494
                                } else if (expr != null && expr.Code == ILCode.Ret) {
822
495
                                        if (expr.Arguments.Count != 1 || expr.Arguments[0].Code != ILCode.Ldc_I4)
823
 
                                                throw new YieldAnalysisFailedException();
 
496
                                                throw new SymbolicAnalysisFailedException();
824
497
                                        // handle direct return (e.g. in release builds)
825
498
                                        int val = (int)expr.Arguments[0].Operand;
826
499
                                        if (val == 0) {
828
501
                                        } else if (val == 1) {
829
502
                                                newBody.Add(MakeGoTo(labels, currentState));
830
503
                                        } else {
831
 
                                                throw new YieldAnalysisFailedException();
 
504
                                                throw new SymbolicAnalysisFailedException();
832
505
                                        }
833
506
                                } else if (expr != null && expr.Code == ILCode.Call && expr.Arguments.Count == 1 && expr.Arguments[0].MatchThis()) {
834
507
                                        MethodDefinition method = GetMethodDefinition(expr.Operand as MethodReference);
835
508
                                        if (method == null)
836
 
                                                throw new YieldAnalysisFailedException();
 
509
                                                throw new SymbolicAnalysisFailedException();
837
510
                                        Interval interval;
838
511
                                        if (method == disposeMethod) {
839
512
                                                // Explicit call to dispose is used for "yield break;" within the method.
840
513
                                                ILExpression br = body.ElementAtOrDefault(++pos) as ILExpression;
841
514
                                                if (br == null || !(br.Code == ILCode.Br || br.Code == ILCode.Leave) || br.Operand != returnFalseLabel)
842
 
                                                        throw new YieldAnalysisFailedException();
 
515
                                                        throw new SymbolicAnalysisFailedException();
843
516
                                                newBody.Add(MakeGoTo(returnFalseLabel));
844
517
                                        } else if (finallyMethodToStateInterval.TryGetValue(method, out interval)) {
845
518
                                                // Call to Finally-method
846
519
                                                int index = stateChanges.FindIndex(ss => ss.NewState >= interval.Start && ss.NewState <= interval.End);
847
520
                                                if (index < 0)
848
 
                                                        throw new YieldAnalysisFailedException();
 
521
                                                        throw new SymbolicAnalysisFailedException();
849
522
                                                
850
523
                                                ILLabel label = new ILLabel();
851
524
                                                label.Name = "JumpOutOfTryFinally" + interval.Start + "_" + interval.End;
883
556
                                if (pair.Value.Contains(state))
884
557
                                        return MakeGoTo(pair.Key);
885
558
                        }
886
 
                        throw new YieldAnalysisFailedException();
 
559
                        throw new SymbolicAnalysisFailedException();
887
560
                }
888
561
                
889
562
                ILBlock ConvertFinallyBlock(MethodDefinition finallyMethod)
908
581
                #region TranslateFieldsToLocalAccess
909
582
                void TranslateFieldsToLocalAccess()
910
583
                {
 
584
                        TranslateFieldsToLocalAccess(newBody, fieldToParameterMap);
 
585
                }
 
586
                
 
587
                internal static void TranslateFieldsToLocalAccess(List<ILNode> newBody, Dictionary<FieldDefinition, ILVariable> fieldToParameterMap)
 
588
                {
911
589
                        var fieldToLocalMap = new DefaultDictionary<FieldDefinition, ILVariable>(f => new ILVariable { Name = f.Name, Type = f.FieldType });
912
590
                        foreach (ILNode node in newBody) {
913
591
                                foreach (ILExpression expr in node.GetSelfAndChildrenRecursive<ILExpression>()) {