1 // 2 // SubroutineBuilder.cs 3 // 4 // Authors: 5 // Alexander Chebaturkin (chebaturkin@gmail.com) 6 // 7 // Copyright (C) 2011 Alexander Chebaturkin 8 // 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: 16 // 17 // The above copyright notice and this permission notice shall be 18 // included in all copies or substantial portions of the Software. 19 // 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. 27 // 28 29 using System.Collections.Generic; 30 using Mono.CodeContracts.Static.AST; 31 using Mono.CodeContracts.Static.ControlFlow.Blocks; 32 using Mono.CodeContracts.Static.DataStructures; 33 using Mono.CodeContracts.Static.Providers; 34 35 namespace Mono.CodeContracts.Static.ControlFlow.Subroutines.Builders { 36 abstract class SubroutineBuilder<Label> { 37 public readonly SubroutineFacade SubroutineFacade; 38 39 private readonly Dictionary<Label, Pair<Method, bool>> labels_for_call_sites = new Dictionary<Label, Pair<Method, bool>> (); 40 private readonly Dictionary<Label, Method> labels_for_new_obj_sites = new Dictionary<Label, Method> (); 41 private readonly HashSet<Label> labels_starting_blocks = new HashSet<Label> (); 42 private readonly HashSet<Label> target_labels = new HashSet<Label> (); 43 SubroutineBuilder(ICodeProvider<Label> codeProvider, SubroutineFacade subroutineFacade, Label entry)44 protected SubroutineBuilder (ICodeProvider<Label> codeProvider, 45 SubroutineFacade subroutineFacade, 46 Label entry) 47 { 48 this.SubroutineFacade = subroutineFacade; 49 CodeProvider = codeProvider; 50 AddTargetLabel (entry); 51 } 52 53 public ICodeProvider<Label> CodeProvider { get; private set; } 54 public abstract SubroutineBase<Label> CurrentSubroutine { get; } 55 56 public IMetaDataProvider MetaDataProvider 57 { 58 get { return this.SubroutineFacade.MetaDataProvider; } 59 } 60 61 protected IContractProvider ContractProvider 62 { 63 get { return this.SubroutineFacade.ContractProvider; } 64 } 65 AddTargetLabel(Label target)66 public void AddTargetLabel (Label target) 67 { 68 AddBlockStart (target); 69 this.target_labels.Add (target); 70 } 71 AddBlockStart(Label target)72 public void AddBlockStart (Label target) 73 { 74 this.labels_starting_blocks.Add (target); 75 } 76 Initialize(Label entry)77 protected void Initialize (Label entry) 78 { 79 new BlockStartGatherer<Label> (this).TraceAggregateSequentally (entry); 80 } 81 IsBlockStart(Label label)82 public bool IsBlockStart (Label label) 83 { 84 return this.labels_starting_blocks.Contains (label); 85 } 86 IsTargetLabel(Label label)87 public bool IsTargetLabel (Label label) 88 { 89 return this.target_labels.Contains (label); 90 } 91 IsMethodCallSite(Label label, out Pair<Method, bool> methodVirtPair)92 public bool IsMethodCallSite (Label label, out Pair<Method, bool> methodVirtPair) 93 { 94 return this.labels_for_call_sites.TryGetValue (label, out methodVirtPair); 95 } 96 IsNewObjSite(Label label, out Method constructor)97 public bool IsNewObjSite (Label label, out Method constructor) 98 { 99 return this.labels_for_new_obj_sites.TryGetValue (label, out constructor); 100 } 101 BuildBlocks(Label entry)102 protected BlockWithLabels<Label> BuildBlocks (Label entry) 103 { 104 return BlockBuilder<Label>.BuildBlocks (entry, this); 105 } 106 RecordInformationSameAsOtherBlock(BlockWithLabels<Label> newBlock, BlockWithLabels<Label> currentBlock)107 public virtual void RecordInformationSameAsOtherBlock (BlockWithLabels<Label> newBlock, BlockWithLabels<Label> currentBlock) 108 { 109 } 110 RecordInformationForNewBlock(Label currentLabel, BlockWithLabels<Label> previousBlock)111 public virtual BlockWithLabels<Label> RecordInformationForNewBlock (Label currentLabel, BlockWithLabels<Label> previousBlock) 112 { 113 BlockWithLabels<Label> block = CurrentSubroutine.GetBlock (currentLabel); 114 if (previousBlock != null) { 115 BlockWithLabels<Label> newBlock = block; 116 BlockWithLabels<Label> prevBlock = previousBlock; 117 if (block is MethodCallBlock<Label> && previousBlock is MethodCallBlock<Label>) { 118 BlockWithLabels<Label> ab = CurrentSubroutine.NewBlock (); 119 RecordInformationSameAsOtherBlock (ab, previousBlock); 120 newBlock = ab; 121 prevBlock = ab; 122 CurrentSubroutine.AddSuccessor (previousBlock, EdgeTag.FallThrough, ab); 123 CurrentSubroutine.AddSuccessor (ab, EdgeTag.FallThrough, block); 124 } else 125 CurrentSubroutine.AddSuccessor (previousBlock, EdgeTag.FallThrough, block); 126 127 InsertPostConditionEdges (previousBlock, newBlock); 128 InsertPreConditionEdges (prevBlock, block); 129 } 130 return block; 131 } 132 InsertPreConditionEdges(BlockWithLabels<Label> previousBlock, BlockWithLabels<Label> newBlock)133 protected void InsertPreConditionEdges (BlockWithLabels<Label> previousBlock, BlockWithLabels<Label> newBlock) 134 { 135 var methodCallBlock = newBlock as MethodCallBlock<Label>; 136 if (methodCallBlock == null || CurrentSubroutine.IsContract || CurrentSubroutine.IsOldValue) 137 return; 138 139 if (CurrentSubroutine.IsMethod) { 140 var methodInfo = CurrentSubroutine as IMethodInfo; 141 Property property; 142 if (methodInfo != null && MetaDataProvider.IsConstructor (methodInfo.Method) 143 && MetaDataProvider.IsPropertySetter (methodCallBlock.CalledMethod, out property) 144 && MetaDataProvider.IsAutoPropertyMember (methodCallBlock.CalledMethod)) 145 return; 146 } 147 148 EdgeTag callTag = methodCallBlock.IsNewObj ? EdgeTag.BeforeNewObj : EdgeTag.BeforeCall; 149 Subroutine requires = this.SubroutineFacade.GetRequires (methodCallBlock.CalledMethod); 150 151 CurrentSubroutine.AddEdgeSubroutine (previousBlock, newBlock, requires, callTag); 152 } 153 InsertPostConditionEdges(BlockWithLabels<Label> previousBlock, BlockWithLabels<Label> newBlock)154 protected void InsertPostConditionEdges (BlockWithLabels<Label> previousBlock, BlockWithLabels<Label> newBlock) 155 { 156 var methodCallBlock = previousBlock as MethodCallBlock<Label>; 157 if (methodCallBlock == null) 158 return; 159 160 if (CurrentSubroutine.IsMethod) { 161 var methodInfo = CurrentSubroutine as IMethodInfo; 162 Property property; 163 if (methodInfo != null && MetaDataProvider.IsConstructor (methodInfo.Method) 164 && MetaDataProvider.IsPropertyGetter (methodCallBlock.CalledMethod, out property) 165 && MetaDataProvider.IsAutoPropertyMember (methodCallBlock.CalledMethod)) 166 return; 167 } 168 169 EdgeTag callTag = methodCallBlock.IsNewObj ? EdgeTag.AfterNewObj : EdgeTag.AfterCall; 170 Subroutine ensures = this.SubroutineFacade.GetEnsures (methodCallBlock.CalledMethod); 171 172 CurrentSubroutine.AddEdgeSubroutine (previousBlock, newBlock, ensures, callTag); 173 } 174 BeginOldHook(Label label)175 public virtual void BeginOldHook (Label label) 176 { 177 } 178 EndOldHook(Label label)179 public virtual void EndOldHook (Label label) 180 { 181 } 182 AddMethodCallSite(Label pc, Pair<Method, bool> methodVirtPair)183 public void AddMethodCallSite (Label pc, Pair<Method, bool> methodVirtPair) 184 { 185 this.labels_for_call_sites [pc] = methodVirtPair; 186 } 187 AddNewObjSite(Label pc, Method method)188 public void AddNewObjSite (Label pc, Method method) 189 { 190 this.labels_for_new_obj_sites [pc] = method; 191 } 192 } 193 } 194