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.AST.Visitors;
33 using Mono.CodeContracts.Static.ControlFlow.Subroutines;
34 using Mono.CodeContracts.Static.DataStructures;
36 namespace Mono.CodeContracts.Static.ControlFlow.Blocks {
37 class EnsuresBlock<Label> : BlockWithLabels<Label> {
38 private const uint Mask = 0xC0000000u;
39 private const uint BeginOldMask = 0x80000000u;
40 private const uint EndOldMask = 0x40000000u;
42 private List<uint> overridingLabels;
44 public EnsuresBlock (SubroutineBase<Label> subroutine, ref int idGen)
45 : base (subroutine, ref idGen)
49 private new EnsuresSubroutine<Label> Subroutine
51 get { return (EnsuresSubroutine<Label>) base.Subroutine; }
54 public override int Count
58 if (this.overridingLabels != null)
59 return this.overridingLabels.Count;
64 public bool UsesOverriding
66 get { return this.overridingLabels != null; }
69 public override bool TryGetLabel (int index, out Label label)
72 if (IsOriginal (index, out originalOffset))
73 return base.TryGetLabel (originalOffset, out label);
74 label = default(Label);
78 public Result OriginalForwardDecode<Data, Result, Visitor> (int index, Visitor visitor, Data data)
79 where Visitor : IAggregateVisitor<Label, Data, Result>
82 if (base.TryGetLabel (index, out label))
83 return Subroutine.CodeProvider.Decode<Visitor, Data, Result> (label, visitor, data);
85 throw new InvalidOperationException ("should not happen");
88 public override Result ForwardDecode<Data, Result, Visitor> (APC pc, Visitor visitor, Data data)
91 if (TryGetLabel (pc.Index, out label))
92 return base.ForwardDecode<Data, Result, Visitor> (pc, visitor, data);
95 if (IsBeginOld (pc.Index, out endOldIndex)) {
96 CFGBlock block = Subroutine.InferredBeginEndBijection (pc);
97 return visitor.BeginOld (pc, new APC (block, endOldIndex, pc.SubroutineContext), data);
101 if (IsEndOld (pc.Index, out beginOldIndex)) {
103 CFGBlock block = Subroutine.InferredBeginEndBijection (pc, out endOldType);
104 return visitor.EndOld (pc, new APC (block, beginOldIndex, pc.SubroutineContext), endOldType, Dummy.Value, Dummy.Value, data);
107 return visitor.Nop (pc, data);
110 private bool IsEndOld (int index, out int beginOldIndex)
112 if (this.overridingLabels != null && index < this.overridingLabels.Count && (this.overridingLabels [index] & EndOldMask) != 0) {
113 beginOldIndex = (int) (this.overridingLabels [index] & (EndOldMask - 1));
121 private bool IsBeginOld (int index, out int endOldIndex)
123 if (this.overridingLabels != null && index < this.overridingLabels.Count && (this.overridingLabels [index] & BeginOldMask) != 0) {
124 endOldIndex = (int) (this.overridingLabels [index] & (EndOldMask - 1));
132 private bool IsOriginal (int index, out int originalOffset)
134 if (this.overridingLabels == null) {
135 originalOffset = index;
138 if (index < this.overridingLabels.Count && (this.overridingLabels [index] & Mask) == 0) {
139 originalOffset = (int) (this.overridingLabels [index] & (EndOldMask - 1));
147 public void StartOverridingLabels ()
149 this.overridingLabels = new List<uint> ();
152 public void BeginOld (int index)
154 if (this.overridingLabels == null) {
155 StartOverridingLabels ();
156 for (int i = 0; i < index; ++i)
157 this.overridingLabels.Add ((uint) i);
159 this.overridingLabels.Add (BeginOldMask);
162 public void AddInstruction (int index)
164 this.overridingLabels.Add ((uint) index);
167 public void EndOld (int index, TypeNode nextEndOldType)
169 AddInstruction (index);
170 EndOldWithoutInstruction (nextEndOldType);
173 public void EndOldWithoutInstruction (TypeNode nextEndOldType)
175 int endOldIndex = this.overridingLabels.Count;
177 this.overridingLabels.Add ((uint) (EndOldMask | PatchPriorBeginOld (this, endOldIndex, out beginBlock)));
178 Subroutine.AddInferredOldMap (this.Index, endOldIndex, beginBlock, nextEndOldType);
181 private int PatchPriorBeginOld (CFGBlock endBlock, int endOldIndex, out CFGBlock beginBlock)
183 for (int i = this == endBlock ? endOldIndex - 2 : Count - 1; i >= 0; i--) {
185 if (IsBeginOld (i, out endOldI)) {
186 this.overridingLabels [i] = BeginOldMask | (uint)endOldIndex;
188 Subroutine.AddInferredOldMap (this.Index, i, endBlock, default(TypeNode));
193 IEnumerator<CFGBlock> enumerator = Subroutine.PredecessorBlocks (this).GetEnumerator ();
194 if (!enumerator.MoveNext ())
195 throw new InvalidOperationException ("missing begin_old");
196 int result = PatchPriorBeginOld (endBlock, endOldIndex, enumerator.Current, out beginBlock);
197 enumerator.MoveNext ();
201 private int PatchPriorBeginOld (CFGBlock endBlock, int endOldIndex, CFGBlock current, out CFGBlock beginBlock)
203 var ensuresBlock = current as EnsuresBlock<Label>;
204 if (ensuresBlock != null)
205 return ensuresBlock.PatchPriorBeginOld (endBlock, endOldIndex, out beginBlock);
206 IEnumerator<CFGBlock> enumerator = current.Subroutine.PredecessorBlocks (current).GetEnumerator ();
207 if (!enumerator.MoveNext ())
208 throw new InvalidOperationException ("missing begin_old");
210 int result = PatchPriorBeginOld (endBlock, endOldIndex, enumerator.Current, out beginBlock);
211 enumerator.MoveNext ();