2 // EnsuresSubroutine.cs
5 // Alexander Chebaturkin (chebaturkin@gmail.com)
7 // Copyright (C) 2011 Alexander Chebaturkin
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 using System.Collections.Generic;
31 using Mono.CodeContracts.Static.AST;
32 using Mono.CodeContracts.Static.ControlFlow.Blocks;
33 using Mono.CodeContracts.Static.ControlFlow.Subroutines.Builders;
34 using Mono.CodeContracts.Static.DataStructures;
36 namespace Mono.CodeContracts.Static.ControlFlow.Subroutines {
37 sealed class EnsuresSubroutine<Label> : MethodContractSubroutine<Label>, IEquatable<EnsuresSubroutine<Label>> {
38 private readonly Dictionary<int, Pair<CFGBlock, TypeNode>> inferred_old_label_reverse_map;
40 public EnsuresSubroutine (SubroutineFacade subroutineFacade,
41 Method method, IImmutableSet<Subroutine> inherited) : base (subroutineFacade, method)
43 this.inferred_old_label_reverse_map = new Dictionary<int, Pair<CFGBlock, TypeNode>> ();
44 AddSuccessor (Entry, EdgeTag.Entry, Exit);
45 AddBaseEnsures (Entry, Exit, inherited);
49 public EnsuresSubroutine (SubroutineFacade subroutineFacade,
51 SimpleSubroutineBuilder<Label> builder, Label startLabel, IImmutableSet<Subroutine> inherited)
52 : base (subroutineFacade, method, builder, startLabel)
54 this.inferred_old_label_reverse_map = new Dictionary<int, Pair<CFGBlock, TypeNode>> ();
55 AddBaseEnsures (Entry, GetTargetBlock (startLabel), inherited);
58 public override SubroutineKind Kind
60 get { return SubroutineKind.Ensures; }
63 public override bool IsEnsures
68 public override bool IsContract
73 #region IEquatable<EnsuresSubroutine<Label>> Members
74 public bool Equals (EnsuresSubroutine<Label> other)
76 return Id == other.Id;
80 private void AddBaseEnsures (CFGBlock from, CFGBlock to, IImmutableSet<Subroutine> inherited)
82 if (inherited == null)
84 foreach (Subroutine subroutine in inherited.Elements)
85 AddEdgeSubroutine (from, to, subroutine, EdgeTag.Inherited);
88 public override void Initialize ()
92 Builder.BuildBlocks (this.StartLabel, this);
97 public override BlockWithLabels<Label> NewBlock ()
99 return new EnsuresBlock<Label> (this, ref this.BlockIdGenerator);
102 public override void Commit ()
106 var visitor = new OldScanStateMachine<Label> (this);
107 EnsuresBlock<Label> priorBlock = null;
109 foreach (CFGBlock block in Blocks) {
110 var ensuresBlock = block as EnsuresBlock<Label>;
111 if (ensuresBlock != null) {
112 priorBlock = ensuresBlock;
113 int count = ensuresBlock.Count;
114 visitor.StartBlock (ensuresBlock);
116 for (int i = 0; i < count; i++) {
117 if (ensuresBlock.OriginalForwardDecode<int, Boolean, OldScanStateMachine<Label>> (i, visitor, i))
118 ensuresBlock.AddInstruction (i);
121 visitor.HandlePotentialCallBlock (block as MethodCallBlock<Label>, priorBlock);
122 foreach (CFGBlock succ in SuccessorBlocks (block))
123 visitor.SetStartState (succ);
127 public void AddInferredOldMap (int blockIndex, int instructionIndex, CFGBlock otherBlock, TypeNode endOldType)
129 this.inferred_old_label_reverse_map.Add (OverlayInstructionKey (blockIndex, instructionIndex), new Pair<CFGBlock, TypeNode> (otherBlock, endOldType));
132 private static int OverlayInstructionKey (int blockIndex, int instructionIndex)
134 return (instructionIndex << 16) + blockIndex;
137 public CFGBlock InferredBeginEndBijection (APC pc)
140 return InferredBeginEndBijection (pc, out endOldType);
143 public CFGBlock InferredBeginEndBijection (APC pc, out TypeNode endOldType)
145 Pair<CFGBlock, TypeNode> pair;
146 if (!this.inferred_old_label_reverse_map.TryGetValue (OverlayInstructionKey (pc.Block.Index, pc.Index), out pair))
147 throw new InvalidOperationException ("Fatal bug in ensures CFG begin/end old map");
148 endOldType = pair.Value;