├── .gitattributes ├── .gitignore ├── Backend ├── Analysis │ ├── BackwardCopyPropagationAnalysis.cs │ ├── ControlFlowGraph.cs │ ├── DataFlowAnalysis.cs │ ├── ForwardCopyPropagationAnalysis.cs │ ├── PointsToAnalysis.cs │ ├── ReachingDefinitionsAnalysis.cs │ ├── StaticSingleAssignmentAnalysis.cs │ ├── SymbolicAnalysis.cs │ ├── TypeInferenceAnalysis.cs │ └── WebAnalysis.cs ├── Backend.csproj ├── Disassembler.cs ├── MethodBody.cs ├── Properties │ └── AssemblyInfo.cs ├── Serialization │ ├── DGMLSerializer.cs │ └── DOTSerializer.cs ├── ThreeAddressCode │ ├── ExceptionHandlers.cs │ ├── Expressions.cs │ ├── Instructions.cs │ ├── Operands.cs │ ├── TypeDefinitions.cs │ └── Types.cs ├── Types.cs ├── TypesExtractor.cs ├── Utils │ ├── Exceptions.cs │ ├── Extensions.cs │ ├── Map.cs │ ├── OperationHelper.cs │ └── Subset.cs └── Visitors │ ├── IInstructionVisitor.cs │ └── InstructionVisitor.cs ├── CCI Backend.sln ├── Console ├── Assembly.cs ├── Console.csproj ├── MethodVisitor.cs ├── Program.cs └── Properties │ └── AssemblyInfo.cs ├── Dependencies ├── Microsoft.Cci.ILGenerator.dll ├── Microsoft.Cci.MetadataHelper.dll ├── Microsoft.Cci.MetadataModel.dll ├── Microsoft.Cci.MutableMetadataModel.dll ├── Microsoft.Cci.PdbReader.dll ├── Microsoft.Cci.PdbWriter.dll ├── Microsoft.Cci.PeReader.dll ├── Microsoft.Cci.PeWriter.dll └── Microsoft.Cci.SourceModel.dll ├── LICENSE.txt ├── README.md ├── Test ├── Examples.cs ├── ExamplesPointsTo.cs ├── Properties │ └── AssemblyInfo.cs └── Test.csproj ├── grammar_tac.txt └── instructions.txt /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto !eol 2 | Backend/Analysis/ControlFlowGraph.cs -text 3 | Backend/Analysis/CopyPropagationAnalysis.cs -text 4 | Backend/Analysis/DataFlowAnalysis.cs -text 5 | Backend/Analysis/PointsToAnalysis.cs -text 6 | Backend/Analysis/ReachingDefinitionsAnalysis.cs -text 7 | Backend/Analysis/StaticSingleAssignmentAnalysis.cs -text 8 | Backend/Analysis/SymbolicAnalysis.cs -text 9 | Backend/Analysis/TypeInferenceAnalysis.cs -text 10 | Backend/Analysis/WebAnalysis.cs -text 11 | Backend/Backend.csproj -text 12 | Backend/Disassembler.cs -text 13 | Backend/MethodBody.cs -text 14 | Backend/Properties/AssemblyInfo.cs -text 15 | Backend/Serialization/DGMLSerializer.cs -text 16 | Backend/Serialization/DOTSerializer.cs -text 17 | Backend/ThreeAddressCode/ExceptionHandlers.cs -text 18 | Backend/ThreeAddressCode/Expressions.cs -text 19 | Backend/ThreeAddressCode/Instructions.cs -text 20 | Backend/ThreeAddressCode/Operands.cs -text 21 | Backend/ThreeAddressCode/TypeDefinitions.cs -text 22 | Backend/ThreeAddressCode/Types.cs -text 23 | Backend/Types.cs -text 24 | Backend/TypesExtractor.cs -text 25 | Backend/Utils/Exceptions.cs -text 26 | Backend/Utils/Extensions.cs -text 27 | Backend/Utils/Map.cs -text 28 | Backend/Utils/OperationHelper.cs -text 29 | Backend/Utils/Subset.cs -text 30 | Backend/Visitors/IInstructionVisitor.cs -text 31 | Backend/Visitors/InstructionVisitor.cs -text 32 | /CCI[!!-~]Backend.sln -text 33 | Console/Assembly.cs -text 34 | Console/Console.csproj -text 35 | Console/MethodVisitor.cs -text 36 | Console/Program.cs -text 37 | Console/Properties/AssemblyInfo.cs -text 38 | Dependencies/Microsoft.Cci.ILGenerator.dll -text 39 | Dependencies/Microsoft.Cci.MetadataHelper.dll -text 40 | Dependencies/Microsoft.Cci.MetadataModel.dll -text 41 | Dependencies/Microsoft.Cci.MutableMetadataModel.dll -text 42 | Dependencies/Microsoft.Cci.PdbReader.dll -text 43 | Dependencies/Microsoft.Cci.PdbWriter.dll -text 44 | Dependencies/Microsoft.Cci.PeReader.dll -text 45 | Dependencies/Microsoft.Cci.PeWriter.dll -text 46 | Dependencies/Microsoft.Cci.SourceModel.dll -text 47 | Test/Examples.cs -text 48 | Test/ExamplesPointsTo.cs -text 49 | Test/Properties/AssemblyInfo.cs -text 50 | Test/Test.csproj -text 51 | /grammar_tac.txt -text 52 | /instructions.txt -text 53 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /*.suo 2 | Backend/*.user 3 | Backend/bin 4 | Backend/obj 5 | Console/*.user 6 | Console/bin 7 | Console/obj 8 | Test/bin 9 | Test/obj 10 | .vs 11 | /packages/CustomMetadataFix.Microsoft.Cci.Metadata.3.0.0 12 | /Model/obj/Debug 13 | /Model/bin/Debug 14 | /CCIProvider/bin/Debug 15 | /CCIProvider/obj/Debug 16 | -------------------------------------------------------------------------------- /Backend/Analysis/BackwardCopyPropagationAnalysis.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Edgardo Zoppi. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. 2 | 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | 8 | using Backend.ThreeAddressCode; 9 | using Backend.Utils; 10 | using Backend.ThreeAddressCode.Values; 11 | using Backend.ThreeAddressCode.Instructions; 12 | 13 | namespace Backend.Analysis 14 | { 15 | //[Obsolete("The analysis implementation could have some bugs!")] 16 | public class BackwardCopyPropagationAnalysis : BackwardDataFlowAnalysis> 17 | { 18 | private DataFlowAnalysisResult>[] result; 19 | private IDictionary[] GEN; 20 | private ISet[] KILL; 21 | 22 | public BackwardCopyPropagationAnalysis(ControlFlowGraph cfg) 23 | : base(cfg) 24 | { 25 | } 26 | 27 | public void Transform(MethodBody body) 28 | { 29 | if (this.result == null) throw new InvalidOperationException("Analysis result not available."); 30 | 31 | foreach (var node in this.cfg.Nodes) 32 | { 33 | var node_result = this.result[node.Id]; 34 | var copies = new Dictionary(); 35 | 36 | if (node_result.Output != null) 37 | { 38 | copies.AddRange(node_result.Output); 39 | } 40 | 41 | for (var i = node.Instructions.Count - 1; i >= 0; --i) 42 | { 43 | var instruction = node.Instructions[i]; 44 | 45 | foreach (var variable in instruction.ModifiedVariables) 46 | { 47 | // Only replace temporal variables 48 | if (variable.IsTemporal() && 49 | copies.ContainsKey(variable)) 50 | { 51 | var operand = copies[variable]; 52 | 53 | instruction.Replace(variable, operand); 54 | } 55 | } 56 | 57 | var isTemporalCopy = this.Flow(instruction, copies); 58 | 59 | foreach (var variable in instruction.UsedVariables) 60 | { 61 | // Only replace temporal variables 62 | if (variable.IsTemporal() && 63 | copies.ContainsKey(variable)) 64 | { 65 | var operand = copies[variable]; 66 | 67 | instruction.Replace(variable, operand); 68 | } 69 | } 70 | 71 | // Only replace temporal variables 72 | if (isTemporalCopy) 73 | { 74 | // Remove the copy instruction 75 | if (i == 0) 76 | { 77 | // The copy is the first instruction of the basic block 78 | // Replace the copy instruction with a nop to preserve branch targets 79 | var nop = new NopInstruction(instruction.Offset); 80 | var index = body.Instructions.IndexOf(instruction); 81 | body.Instructions[index] = nop; 82 | node.Instructions[i] = nop; 83 | } 84 | else 85 | { 86 | // The copy is not the first instruction of the basic block 87 | body.Instructions.Remove(instruction); 88 | node.Instructions.RemoveAt(i); 89 | } 90 | } 91 | } 92 | } 93 | 94 | body.UpdateVariables(); 95 | } 96 | 97 | public override DataFlowAnalysisResult>[] Analyze() 98 | { 99 | this.ComputeGen(); 100 | this.ComputeKill(); 101 | 102 | var result = base.Analyze(); 103 | 104 | this.result = result; 105 | this.GEN = null; 106 | this.KILL = null; 107 | 108 | return result; 109 | } 110 | 111 | protected override IDictionary InitialValue(CFGNode node) 112 | { 113 | return GEN[node.Id]; 114 | } 115 | 116 | protected override bool Compare(IDictionary left, IDictionary right) 117 | { 118 | return left.DictionaryEquals(right); 119 | } 120 | 121 | protected override IDictionary Join(IDictionary left, IDictionary right) 122 | { 123 | // result = intersection(left, right) 124 | var result = new Dictionary(); 125 | 126 | foreach (var copy in left) 127 | { 128 | var variable = copy.Key; 129 | var leftOperand = copy.Value; 130 | 131 | if (right.ContainsKey(variable)) 132 | { 133 | var rightOperand = right[variable]; 134 | 135 | if (leftOperand.Equals(rightOperand)) 136 | { 137 | result.Add(variable, leftOperand); 138 | } 139 | } 140 | } 141 | 142 | return result; 143 | } 144 | 145 | protected override IDictionary Flow(CFGNode node, IDictionary output) 146 | { 147 | var input = new Dictionary(output); 148 | var kill = KILL[node.Id]; 149 | var gen = GEN[node.Id]; 150 | 151 | foreach (var variable in kill) 152 | { 153 | this.RemoveCopiesWithVariable(input, variable); 154 | } 155 | 156 | input.AddRange(gen); 157 | return input; 158 | } 159 | 160 | private void ComputeGen() 161 | { 162 | GEN = new IDictionary[this.cfg.Nodes.Count]; 163 | 164 | foreach (var node in this.cfg.Nodes) 165 | { 166 | var gen = new Dictionary(); 167 | 168 | for (var i = node.Instructions.Count - 1; i >= 0; --i) 169 | { 170 | var instruction = node.Instructions[i]; 171 | this.Flow(instruction, gen); 172 | } 173 | 174 | GEN[node.Id] = gen; 175 | } 176 | } 177 | 178 | private void ComputeKill() 179 | { 180 | KILL = new ISet[this.cfg.Nodes.Count]; 181 | 182 | foreach (var node in this.cfg.Nodes) 183 | { 184 | var kill = new HashSet(); 185 | 186 | foreach (var instruction in node.Instructions) 187 | { 188 | kill.UnionWith(instruction.ModifiedVariables); 189 | } 190 | 191 | KILL[node.Id] = kill; 192 | } 193 | } 194 | 195 | private void RemoveCopiesWithVariable(IDictionary copies, IVariable variable) 196 | { 197 | var array = copies.ToArray(); 198 | 199 | foreach (var copy in array) 200 | { 201 | if (copy.Key == variable || 202 | copy.Value == variable) 203 | { 204 | copies.Remove(copy.Key); 205 | } 206 | } 207 | } 208 | 209 | private bool Flow(Instruction instruction, IDictionary copies) 210 | { 211 | IVariable left; 212 | IVariable right; 213 | 214 | var isCopy = instruction.IsCopy(out left, out right); 215 | 216 | if (isCopy) 217 | { 218 | // Only replace temporal variables 219 | if (left.IsTemporal() && 220 | copies.ContainsKey(left)) 221 | { 222 | left = copies[left]; 223 | } 224 | } 225 | 226 | foreach (var variable in instruction.ModifiedVariables) 227 | { 228 | this.RemoveCopiesWithVariable(copies, variable); 229 | } 230 | 231 | if (isCopy) 232 | { 233 | this.RemoveCopiesWithVariable(copies, right); 234 | copies.Add(right, left); 235 | } 236 | 237 | var result = isCopy && right.IsTemporal(); 238 | return result; 239 | } 240 | } 241 | } 242 | -------------------------------------------------------------------------------- /Backend/Analysis/ControlFlowGraph.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Edgardo Zoppi. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. 2 | 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Collections; 8 | 9 | using Backend.ThreeAddressCode; 10 | using Backend.Utils; 11 | using Backend.ThreeAddressCode.Instructions; 12 | using Backend.Visitors; 13 | 14 | namespace Backend.Analysis 15 | { 16 | public enum CFGNodeKind 17 | { 18 | Entry, 19 | Exit, 20 | BasicBlock 21 | } 22 | 23 | public class CFGLoop 24 | { 25 | public CFGNode Header { get; set; } 26 | public ISet Body { get; private set; } 27 | //public IExpression Condition { get; set; } 28 | 29 | public CFGLoop(CFGNode header) 30 | { 31 | this.Header = header; 32 | this.Body = new HashSet(); 33 | this.Body.Add(header); 34 | } 35 | 36 | public override string ToString() 37 | { 38 | var sb = new StringBuilder(" "); 39 | 40 | foreach (var node in this.Body) 41 | { 42 | sb.AppendFormat("B{0} ", node.Id); 43 | } 44 | 45 | return sb.ToString(); 46 | } 47 | } 48 | 49 | public class CFGEdge 50 | { 51 | public CFGNode Source { get; set; } 52 | public CFGNode Target { get; set; } 53 | 54 | public CFGEdge(CFGNode source, CFGNode target) 55 | { 56 | this.Source = source; 57 | this.Target = target; 58 | } 59 | 60 | public override string ToString() 61 | { 62 | return string.Format("{0} -> {1}", this.Source, this.Target); 63 | } 64 | } 65 | 66 | public class CFGNode : IInstructionContainer 67 | { 68 | private ISet dominators; 69 | 70 | public int Id { get; private set; } 71 | public int ForwardIndex { get; set; } 72 | public int BackwardIndex { get; set; } 73 | public CFGNodeKind Kind { get; private set; } 74 | public ISet Predecessors { get; private set; } 75 | public ISet Successors { get; private set; } 76 | public IList Instructions { get; private set; } 77 | public CFGNode ImmediateDominator { get; set; } 78 | public ISet ImmediateDominated { get; private set; } 79 | public ISet DominanceFrontier { get; private set; } 80 | 81 | public CFGNode(int id, CFGNodeKind kind = CFGNodeKind.BasicBlock) 82 | { 83 | this.Id = id; 84 | this.Kind = kind; 85 | this.ForwardIndex = -1; 86 | this.BackwardIndex = -1; 87 | this.Predecessors = new HashSet(); 88 | this.Successors = new HashSet(); 89 | this.Instructions = new List(); 90 | this.ImmediateDominated = new HashSet(); 91 | this.DominanceFrontier = new HashSet(); 92 | } 93 | 94 | public ISet Dominators 95 | { 96 | get 97 | { 98 | if (this.dominators == null) 99 | { 100 | this.dominators = CFGNode.ComputeDominators(this); 101 | } 102 | 103 | return this.dominators; 104 | } 105 | } 106 | 107 | public override string ToString() 108 | { 109 | string result; 110 | 111 | switch (this.Kind) 112 | { 113 | case CFGNodeKind.Entry: result = "entry"; break; 114 | case CFGNodeKind.Exit: result = "exit"; break; 115 | default: result = string.Join("\n", this.Instructions); break; 116 | } 117 | 118 | return result; 119 | } 120 | 121 | private static ISet ComputeDominators(CFGNode node) 122 | { 123 | var result = new HashSet(); 124 | 125 | do 126 | { 127 | result.Add(node); 128 | node = node.ImmediateDominator; 129 | } 130 | while (node != null); 131 | 132 | return result; 133 | } 134 | } 135 | 136 | public class ControlFlowGraph 137 | { 138 | private CFGNode[] forwardOrder; 139 | private CFGNode[] backwardOrder; 140 | 141 | public CFGNode Entry { get; private set; } 142 | public CFGNode Exit { get; private set; } 143 | public ISet Nodes { get; private set; } 144 | public ISet Loops { get; private set; } 145 | 146 | public ControlFlowGraph() 147 | { 148 | this.Entry = new CFGNode(0, CFGNodeKind.Entry); 149 | this.Exit = new CFGNode(1, CFGNodeKind.Exit); 150 | this.Nodes = new HashSet() { this.Entry, this.Exit }; 151 | this.Loops = new HashSet(); 152 | } 153 | 154 | public IEnumerable Entries 155 | { 156 | get 157 | { 158 | var result = from node in this.Nodes 159 | where node.Predecessors.Count == 0 160 | select node; 161 | 162 | return result; 163 | } 164 | } 165 | 166 | public IEnumerable Exits 167 | { 168 | get 169 | { 170 | var result = from node in this.Nodes 171 | where node.Successors.Count == 0 172 | select node; 173 | 174 | return result; 175 | } 176 | } 177 | 178 | public CFGNode[] ForwardOrder 179 | { 180 | get 181 | { 182 | if (this.forwardOrder == null) 183 | { 184 | this.forwardOrder = ControlFlowGraph.ComputeForwardTopologicalSort(this); 185 | } 186 | 187 | return this.forwardOrder; 188 | } 189 | } 190 | 191 | public CFGNode[] BackwardOrder 192 | { 193 | get 194 | { 195 | if (this.backwardOrder == null) 196 | { 197 | this.backwardOrder = ControlFlowGraph.ComputeBackwardTopologicalSort(this); 198 | } 199 | 200 | return this.backwardOrder; 201 | } 202 | } 203 | 204 | #region Generation 205 | 206 | public static ControlFlowGraph GenerateNormalControlFlow(MethodBody method) 207 | { 208 | var instructions = ControlFlowGraph.FilterExceptionHandlers(method); 209 | var leaders = ControlFlowGraph.CreateNodes(instructions); 210 | var cfg = ControlFlowGraph.ConnectNodes(instructions, leaders); 211 | 212 | return cfg; 213 | } 214 | 215 | public static ControlFlowGraph GenerateExceptionalControlFlow(MethodBody method) 216 | { 217 | var instructions = method.Instructions; 218 | var leaders = ControlFlowGraph.CreateNodes(instructions); 219 | var cfg = ControlFlowGraph.ConnectNodes(instructions, leaders); 220 | ControlFlowGraph.ConnectNodesWithExceptionHandlers(cfg, method.ProtectedBlocks, leaders); 221 | 222 | return cfg; 223 | } 224 | 225 | private static IList FilterExceptionHandlers(MethodBody method) 226 | { 227 | var instructions = new List(); 228 | var handlers = method.ProtectedBlocks.Select(h => h.Handler).ToDictionary(h => h.Start); 229 | var i = 0; 230 | 231 | while (i < method.Instructions.Count) 232 | { 233 | var instruction = method.Instructions[i]; 234 | 235 | if (handlers.ContainsKey(instruction.Label)) 236 | { 237 | var handler = handlers[instruction.Label]; 238 | 239 | do 240 | { 241 | i++; 242 | instruction = method.Instructions[i]; 243 | } 244 | while (!instruction.Label.Equals(handler.End)); 245 | } 246 | else 247 | { 248 | instructions.Add(instruction); 249 | i++; 250 | } 251 | } 252 | 253 | return instructions; 254 | } 255 | 256 | private static IDictionary CreateNodes(IEnumerable instructions) 257 | { 258 | var leaders = new Dictionary(); 259 | var nextIsLeader = true; 260 | var nodeId = 2; 261 | 262 | foreach (var instruction in instructions) 263 | { 264 | var isLeader = nextIsLeader; 265 | nextIsLeader = false; 266 | 267 | if (instruction is TryInstruction || 268 | instruction is CatchInstruction || 269 | instruction is FinallyInstruction) 270 | { 271 | isLeader = true; 272 | } 273 | 274 | if (isLeader && !leaders.ContainsKey(instruction.Label)) 275 | { 276 | var node = new CFGNode(nodeId++); 277 | leaders.Add(instruction.Label, node); 278 | } 279 | 280 | if (instruction is UnconditionalBranchInstruction || 281 | instruction is ConditionalBranchInstruction) 282 | { 283 | nextIsLeader = true; 284 | var branch = instruction as BranchInstruction; 285 | 286 | if (!leaders.ContainsKey(branch.Target)) 287 | { 288 | var node = new CFGNode(nodeId++); 289 | leaders.Add(branch.Target, node); 290 | } 291 | } 292 | else if (instruction is SwitchInstruction) 293 | { 294 | nextIsLeader = true; 295 | var branch = instruction as SwitchInstruction; 296 | 297 | foreach (var target in branch.Targets) 298 | { 299 | if (!leaders.ContainsKey(target)) 300 | { 301 | var node = new CFGNode(nodeId++); 302 | leaders.Add(target, node); 303 | } 304 | } 305 | } 306 | else if (instruction is ReturnInstruction || 307 | instruction is ThrowInstruction) 308 | { 309 | nextIsLeader = true; 310 | } 311 | } 312 | 313 | return leaders; 314 | } 315 | 316 | private static ControlFlowGraph ConnectNodes(IEnumerable instructions, IDictionary leaders) 317 | { 318 | var cfg = new ControlFlowGraph(); 319 | var connectWithPreviousNode = true; 320 | var current = cfg.Entry; 321 | CFGNode previous; 322 | 323 | foreach (var instruction in instructions) 324 | { 325 | if (leaders.ContainsKey(instruction.Label)) 326 | { 327 | previous = current; 328 | current = leaders[instruction.Label]; 329 | 330 | // A node cannot fallthrough itself, 331 | // unless it contains another 332 | // instruction with the same label 333 | // of the node's leader instruction 334 | if (connectWithPreviousNode && previous.Id != current.Id) 335 | { 336 | cfg.ConnectNodes(previous, current); 337 | } 338 | } 339 | 340 | connectWithPreviousNode = true; 341 | current.Instructions.Add(instruction); 342 | 343 | if (instruction is BranchInstruction) 344 | { 345 | var branch = instruction as BranchInstruction; 346 | var target = leaders[branch.Target]; 347 | 348 | cfg.ConnectNodes(current, target); 349 | 350 | if (branch is UnconditionalBranchInstruction) 351 | { 352 | connectWithPreviousNode = false; 353 | } 354 | } 355 | else if (instruction is SwitchInstruction) 356 | { 357 | var branch = instruction as SwitchInstruction; 358 | 359 | foreach (var label in branch.Targets) 360 | { 361 | var target = leaders[label]; 362 | 363 | cfg.ConnectNodes(current, target); 364 | } 365 | } 366 | else if (instruction is ReturnInstruction || 367 | instruction is ThrowInstruction) 368 | { 369 | //TODO: not always connect to exit, could exists a catch or finally block 370 | cfg.ConnectNodes(current, cfg.Exit); 371 | } 372 | } 373 | 374 | cfg.ConnectNodes(current, cfg.Exit); 375 | return cfg; 376 | } 377 | 378 | private static void ConnectNodesWithExceptionHandlers(ControlFlowGraph cfg, IEnumerable protectedBlocks, IDictionary leaders) 379 | { 380 | var activeProtectedBlocks = new HashSet(); 381 | var protectedBlocksStart = protectedBlocks.ToLookup(pb => pb.Start); 382 | var protectedBlocksEnd = protectedBlocks.ToLookup(pb => pb.End); 383 | 384 | foreach (var entry in leaders) 385 | { 386 | var label = entry.Key; 387 | var node = entry.Value; 388 | 389 | if (protectedBlocksStart.Contains(label)) 390 | { 391 | var startingProtectedBlocks = protectedBlocksStart[label]; 392 | activeProtectedBlocks.UnionWith(startingProtectedBlocks); 393 | } 394 | 395 | if (protectedBlocksEnd.Contains(label)) 396 | { 397 | var endingProtectedBlocks = protectedBlocksEnd[label]; 398 | activeProtectedBlocks.ExceptWith(endingProtectedBlocks); 399 | } 400 | 401 | // Connect each node inside a try block to the first corresponding handler block 402 | foreach (var block in activeProtectedBlocks) 403 | { 404 | var target = leaders[block.Handler.Start]; 405 | cfg.ConnectNodes(node, target); 406 | } 407 | } 408 | } 409 | 410 | #endregion 411 | 412 | #region Topological Sort 413 | 414 | //private static CFGNode[] ComputeForwardTopologicalSort(ControlFlowGraph cfg) 415 | //{ 416 | // var result = new CFGNode[cfg.Nodes.Count]; 417 | // var visited = new bool[cfg.Nodes.Count]; 418 | // var index = cfg.Nodes.Count - 1; 419 | 420 | // foreach (var node in cfg.Entries) 421 | // { 422 | // ControlFlowGraph.DepthFirstSearch(result, visited, node, ref index); 423 | // } 424 | 425 | // return result; 426 | //} 427 | 428 | //private static void DepthFirstSearch(CFGNode[] result, bool[] visited, CFGNode node, ref int index) 429 | //{ 430 | // var alreadyVisited = visited[node.Id]; 431 | 432 | // if (!alreadyVisited) 433 | // { 434 | // visited[node.Id] = true; 435 | 436 | // foreach (var succ in node.Successors) 437 | // { 438 | // ControlFlowGraph.DepthFirstSearch(result, visited, succ, ref index); 439 | // } 440 | 441 | // node.ForwardIndex = index; 442 | // result[index] = node; 443 | // index--; 444 | // } 445 | //} 446 | 447 | private enum TopologicalSortNodeStatus 448 | { 449 | NeverVisited, // never pushed into stack 450 | FirstVisit, // pushed into stack for the first time 451 | SecondVisit // pushed into stack for the second time 452 | } 453 | 454 | private static CFGNode[] ComputeForwardTopologicalSort(ControlFlowGraph cfg) 455 | { 456 | // reverse postorder traversal from entry node 457 | var stack = new Stack(); 458 | var result = new CFGNode[cfg.Nodes.Count]; 459 | var status = new TopologicalSortNodeStatus[cfg.Nodes.Count]; 460 | var index = cfg.Nodes.Count - 1; 461 | 462 | foreach (var node in cfg.Entries) 463 | { 464 | stack.Push(node); 465 | status[node.Id] = TopologicalSortNodeStatus.FirstVisit; 466 | } 467 | 468 | do 469 | { 470 | var node = stack.Peek(); 471 | var node_status = status[node.Id]; 472 | 473 | if (node_status == TopologicalSortNodeStatus.FirstVisit) 474 | { 475 | status[node.Id] = TopologicalSortNodeStatus.SecondVisit; 476 | 477 | foreach (var succ in node.Successors) 478 | { 479 | var succ_status = status[succ.Id]; 480 | 481 | if (succ_status == TopologicalSortNodeStatus.NeverVisited) 482 | { 483 | stack.Push(succ); 484 | status[succ.Id] = TopologicalSortNodeStatus.FirstVisit; 485 | } 486 | } 487 | } 488 | else if (node_status == TopologicalSortNodeStatus.SecondVisit) 489 | { 490 | stack.Pop(); 491 | node.ForwardIndex = index; 492 | result[index] = node; 493 | index--; 494 | } 495 | } 496 | while (stack.Count > 0); 497 | 498 | return result; 499 | } 500 | 501 | private static CFGNode[] ComputeBackwardTopologicalSort(ControlFlowGraph cfg) 502 | { 503 | // reverse postorder traversal from exit node 504 | var stack = new Stack(); 505 | var result = new CFGNode[cfg.Nodes.Count]; 506 | var status = new TopologicalSortNodeStatus[cfg.Nodes.Count]; 507 | var index = cfg.Nodes.Count - 1; 508 | 509 | foreach (var node in cfg.Exits) 510 | { 511 | stack.Push(node); 512 | status[node.Id] = TopologicalSortNodeStatus.FirstVisit; 513 | } 514 | 515 | do 516 | { 517 | var node = stack.Peek(); 518 | var node_status = status[node.Id]; 519 | 520 | if (node_status == TopologicalSortNodeStatus.FirstVisit) 521 | { 522 | status[node.Id] = TopologicalSortNodeStatus.SecondVisit; 523 | 524 | foreach (var pred in node.Predecessors) 525 | { 526 | var pred_status = status[pred.Id]; 527 | 528 | if (pred_status == TopologicalSortNodeStatus.NeverVisited) 529 | { 530 | stack.Push(pred); 531 | status[pred.Id] = TopologicalSortNodeStatus.FirstVisit; 532 | } 533 | } 534 | } 535 | else if (node_status == TopologicalSortNodeStatus.SecondVisit) 536 | { 537 | stack.Pop(); 538 | node.BackwardIndex = index; 539 | result[index] = node; 540 | index--; 541 | } 542 | } 543 | while (stack.Count > 0); 544 | 545 | return result; 546 | } 547 | 548 | #endregion 549 | 550 | #region Dominance 551 | 552 | public static void ComputeDominators(ControlFlowGraph cfg) 553 | { 554 | bool changed; 555 | var sorted_nodes = cfg.ForwardOrder; 556 | 557 | cfg.Entry.ImmediateDominator = cfg.Entry; 558 | 559 | do 560 | { 561 | changed = false; 562 | 563 | // Skip first node: entry 564 | for (var i = 1; i < sorted_nodes.Length; ++i) 565 | { 566 | var node = sorted_nodes[i]; 567 | var predecessors = node.Predecessors.Where(p => p.ImmediateDominator != null); 568 | var new_idom = predecessors.First(); 569 | predecessors = predecessors.Skip(1); 570 | 571 | foreach (var pred in predecessors) 572 | { 573 | new_idom = ControlFlowGraph.FindCommonAncestor(pred, new_idom); 574 | } 575 | 576 | var old_idom = node.ImmediateDominator; 577 | var equals = old_idom != null && old_idom.Equals(new_idom); 578 | 579 | if (!equals) 580 | { 581 | node.ImmediateDominator = new_idom; 582 | changed = true; 583 | } 584 | } 585 | } 586 | while (changed); 587 | 588 | cfg.Entry.ImmediateDominator = null; 589 | } 590 | 591 | private static CFGNode FindCommonAncestor(CFGNode a, CFGNode b) 592 | { 593 | while (a.ForwardIndex != b.ForwardIndex) 594 | { 595 | while (a.ForwardIndex > b.ForwardIndex) 596 | a = a.ImmediateDominator; 597 | 598 | while (b.ForwardIndex > a.ForwardIndex) 599 | b = b.ImmediateDominator; 600 | } 601 | 602 | return a; 603 | } 604 | 605 | //public static void ComputeDominators(ControlFlowGraph cfg) 606 | //{ 607 | // bool changed; 608 | // var sorted_nodes = cfg.ForwardOrder; 609 | // var result = new Subset[sorted_nodes.Length]; 610 | 611 | // var entry_dom = sorted_nodes.ToEmptySubset(); 612 | // entry_dom.Add(cfg.Entry.Id); 613 | // result[cfg.Entry.Id] = entry_dom; 614 | 615 | // // Skip first node: entry 616 | // for (var i = 1; i < sorted_nodes.Length; ++i) 617 | // { 618 | // result[i] = sorted_nodes.ToSubset(); 619 | // } 620 | 621 | // do 622 | // { 623 | // changed = false; 624 | 625 | // // Skip first node: entry 626 | // for (var i = 1; i < sorted_nodes.Length; ++i) 627 | // { 628 | // var node = sorted_nodes[i]; 629 | // var old_dom = result[node.Id]; 630 | // var new_dom = sorted_nodes.ToSubset(); 631 | 632 | // foreach (var pred in node.Predecessors) 633 | // { 634 | // var pre_dom = result[pred.Id]; 635 | // new_dom.Intersect(pre_dom); 636 | // } 637 | 638 | // new_dom.Add(node.Id); 639 | // var equals = old_dom.Equals(new_dom); 640 | 641 | // if (!equals) 642 | // { 643 | // result[node.Id] = new_dom; 644 | // changed = true; 645 | // } 646 | // } 647 | // } 648 | // while (changed); 649 | 650 | // for (var i = 0; i < sorted_nodes.Length; ++i) 651 | // { 652 | // var node = sorted_nodes[i]; 653 | // var node_dom = result[node.Id]; 654 | 655 | // node_dom.ToSet(node.Dominators); 656 | // } 657 | //} 658 | 659 | #endregion 660 | 661 | #region Dominator Tree 662 | 663 | public static void ComputeDominatorTree(ControlFlowGraph cfg) 664 | { 665 | foreach (var node in cfg.Nodes) 666 | { 667 | if (node.ImmediateDominator == null) continue; 668 | 669 | node.ImmediateDominator.ImmediateDominated.Add(node); 670 | } 671 | } 672 | 673 | #endregion 674 | 675 | #region Dominance Frontier 676 | 677 | public static void ComputeDominanceFrontiers(ControlFlowGraph cfg) 678 | { 679 | foreach (var node in cfg.Nodes) 680 | { 681 | node.DominanceFrontier.Clear(); 682 | } 683 | 684 | foreach (var node in cfg.Nodes) 685 | { 686 | if (node.Predecessors.Count < 2) continue; 687 | 688 | foreach (var pred in node.Predecessors) 689 | { 690 | var runner = pred; 691 | 692 | while (runner.Id != node.ImmediateDominator.Id) 693 | { 694 | runner.DominanceFrontier.Add(node); 695 | runner = runner.ImmediateDominator; 696 | } 697 | } 698 | } 699 | } 700 | 701 | #endregion 702 | 703 | #region Loops 704 | 705 | public static void IdentifyLoops(ControlFlowGraph cfg) 706 | { 707 | cfg.Loops = new HashSet(); 708 | var back_edges = ControlFlowGraph.IdentifyBackEdges(cfg); 709 | 710 | foreach (var edge in back_edges) 711 | { 712 | var loop = ControlFlowGraph.IdentifyLoop(edge); 713 | cfg.Loops.Add(loop); 714 | } 715 | } 716 | 717 | private static ISet IdentifyBackEdges(ControlFlowGraph cfg) 718 | { 719 | var back_edges = new HashSet(); 720 | 721 | foreach (var node in cfg.Nodes) 722 | { 723 | foreach (var succ in node.Successors) 724 | { 725 | if (node.Dominators.Contains(succ)) 726 | { 727 | var edge = new CFGEdge(node, succ); 728 | back_edges.Add(edge); 729 | } 730 | } 731 | } 732 | 733 | return back_edges; 734 | } 735 | 736 | private static CFGLoop IdentifyLoop(CFGEdge back_edge) 737 | { 738 | var loop = new CFGLoop(back_edge.Target); 739 | var nodes = new Stack(); 740 | 741 | nodes.Push(back_edge.Source); 742 | 743 | do 744 | { 745 | var node = nodes.Pop(); 746 | var new_node = loop.Body.Add(node); 747 | 748 | if (new_node) 749 | { 750 | foreach (var pred in node.Predecessors) 751 | { 752 | nodes.Push(pred); 753 | } 754 | } 755 | } 756 | while (nodes.Count > 0); 757 | 758 | return loop; 759 | } 760 | 761 | #endregion 762 | 763 | public void ConnectNodes(CFGNode predecessor, CFGNode successor) 764 | { 765 | successor.Predecessors.Add(predecessor); 766 | predecessor.Successors.Add(successor); 767 | this.Nodes.Add(predecessor); 768 | this.Nodes.Add(successor); 769 | } 770 | } 771 | } 772 | -------------------------------------------------------------------------------- /Backend/Analysis/DataFlowAnalysis.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Edgardo Zoppi. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. 2 | 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | 8 | namespace Backend.Analysis 9 | { 10 | public class DataFlowAnalysisResult 11 | { 12 | public T Input { get; set; } 13 | public T Output { get; set; } 14 | } 15 | 16 | public abstract class DataFlowAnalysis 17 | { 18 | protected ControlFlowGraph cfg; 19 | 20 | public DataFlowAnalysis(ControlFlowGraph cfg) 21 | { 22 | this.cfg = cfg; 23 | } 24 | 25 | public abstract DataFlowAnalysisResult[] Analyze(); 26 | 27 | protected abstract T InitialValue(CFGNode node); 28 | 29 | protected abstract bool Compare(T left, T right); 30 | 31 | protected abstract T Join(T left, T right); 32 | 33 | protected abstract T Flow(CFGNode node, T input); 34 | } 35 | 36 | public abstract class ForwardDataFlowAnalysis : DataFlowAnalysis 37 | { 38 | public ForwardDataFlowAnalysis(ControlFlowGraph cfg) 39 | : base(cfg) 40 | { 41 | } 42 | 43 | public override DataFlowAnalysisResult[] Analyze() 44 | { 45 | var sorted_nodes = this.cfg.ForwardOrder; 46 | var pending_nodes = new Queue(); 47 | var result = new DataFlowAnalysisResult[sorted_nodes.Length]; 48 | 49 | for (var i = 0; i < sorted_nodes.Length; ++i) 50 | { 51 | var node = sorted_nodes[i]; 52 | var node_result = new DataFlowAnalysisResult(); 53 | 54 | node_result.Output = this.InitialValue(node); 55 | result[node.Id] = node_result; 56 | 57 | if (node.Predecessors.Count > 0) 58 | { 59 | pending_nodes.Enqueue(node); 60 | } 61 | } 62 | 63 | while (pending_nodes.Count > 0) 64 | { 65 | var node = pending_nodes.Dequeue(); 66 | var node_result = result[node.Id]; 67 | 68 | //if (node.Predecessors.Count > 0) 69 | { 70 | var first_pred = node.Predecessors.First(); 71 | var other_predecessors = node.Predecessors.Skip(1); 72 | var pred_result = result[first_pred.Id]; 73 | var node_input = pred_result.Output; 74 | 75 | foreach (var pred in other_predecessors) 76 | { 77 | pred_result = result[pred.Id]; 78 | node_input = this.Join(node_input, pred_result.Output); 79 | } 80 | 81 | node_result.Input = node_input; 82 | } 83 | 84 | var old_output = node_result.Output; 85 | var new_output = this.Flow(node, node_result.Input); 86 | var equals = this.Compare(new_output, old_output); 87 | 88 | if (!equals) 89 | { 90 | node_result.Output = new_output; 91 | 92 | foreach (var succ in node.Successors) 93 | { 94 | if (pending_nodes.Contains(succ)) continue; 95 | pending_nodes.Enqueue(succ); 96 | } 97 | } 98 | } 99 | 100 | return result; 101 | } 102 | } 103 | 104 | public abstract class BackwardDataFlowAnalysis : DataFlowAnalysis 105 | { 106 | public BackwardDataFlowAnalysis(ControlFlowGraph cfg) 107 | : base(cfg) 108 | { 109 | } 110 | 111 | public override DataFlowAnalysisResult[] Analyze() 112 | { 113 | var sorted_nodes = this.cfg.BackwardOrder; 114 | var pending_nodes = new Queue(); 115 | var result = new DataFlowAnalysisResult[sorted_nodes.Length]; 116 | 117 | for (var i = 0; i < sorted_nodes.Length; ++i) 118 | { 119 | var node = sorted_nodes[i]; 120 | var node_result = new DataFlowAnalysisResult(); 121 | 122 | node_result.Input = this.InitialValue(node); 123 | result[node.Id] = node_result; 124 | 125 | if (node.Successors.Count > 0) 126 | { 127 | pending_nodes.Enqueue(node); 128 | } 129 | } 130 | 131 | while (pending_nodes.Count > 0) 132 | { 133 | var node = pending_nodes.Dequeue(); 134 | var node_result = result[node.Id]; 135 | 136 | //if (node.Successors.Count > 0) 137 | { 138 | var first_succ = node.Successors.First(); 139 | var other_successors = node.Successors.Skip(1); 140 | var succ_result = result[first_succ.Id]; 141 | var node_output = succ_result.Input; 142 | 143 | foreach (var succ in other_successors) 144 | { 145 | succ_result = result[succ.Id]; 146 | node_output = this.Join(node_output, succ_result.Input); 147 | } 148 | 149 | node_result.Output = node_output; 150 | } 151 | 152 | var old_input = node_result.Input; 153 | var new_input = this.Flow(node, node_result.Output); 154 | var equals = this.Compare(new_input, old_input); 155 | 156 | if (!equals) 157 | { 158 | node_result.Input = new_input; 159 | 160 | foreach (var pred in node.Predecessors) 161 | { 162 | if (pending_nodes.Contains(pred)) continue; 163 | pending_nodes.Enqueue(pred); 164 | } 165 | } 166 | } 167 | 168 | return result; 169 | } 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /Backend/Analysis/ForwardCopyPropagationAnalysis.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Edgardo Zoppi. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. 2 | 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | 8 | using Backend.ThreeAddressCode; 9 | using Backend.Utils; 10 | using Backend.ThreeAddressCode.Values; 11 | using Backend.ThreeAddressCode.Instructions; 12 | 13 | namespace Backend.Analysis 14 | { 15 | public class ForwardCopyPropagationAnalysis : ForwardDataFlowAnalysis> 16 | { 17 | private DataFlowAnalysisResult>[] result; 18 | private IDictionary[] GEN; 19 | private ISet[] KILL; 20 | 21 | public ForwardCopyPropagationAnalysis(ControlFlowGraph cfg) 22 | : base(cfg) 23 | { 24 | } 25 | 26 | public void Transform(MethodBody body) 27 | { 28 | if (this.result == null) throw new InvalidOperationException("Analysis result not available."); 29 | 30 | foreach (var node in this.cfg.Nodes) 31 | { 32 | var node_result = this.result[node.Id]; 33 | var copies = new Dictionary(); 34 | 35 | if (node_result.Input != null) 36 | { 37 | copies.AddRange(node_result.Input); 38 | } 39 | 40 | for (var i = 0; i < node.Instructions.Count; ++i) 41 | { 42 | var instruction = node.Instructions[i]; 43 | 44 | foreach (var variable in instruction.UsedVariables) 45 | { 46 | // Only replace temporal variables 47 | if (variable.IsTemporal() && 48 | copies.ContainsKey(variable)) 49 | { 50 | var operand = copies[variable]; 51 | 52 | instruction.Replace(variable, operand); 53 | } 54 | } 55 | 56 | var isTemporalCopy = this.Flow(instruction, copies); 57 | 58 | // Only replace temporal variables 59 | if (isTemporalCopy) 60 | { 61 | // Remove the copy instruction 62 | if (i == 0) 63 | { 64 | // The copy is the first instruction of the basic block 65 | // Replace the copy instruction with a nop to preserve branch targets 66 | var nop = new NopInstruction(instruction.Offset); 67 | var index = body.Instructions.IndexOf(instruction); 68 | body.Instructions[index] = nop; 69 | node.Instructions[i] = nop; 70 | } 71 | else 72 | { 73 | // The copy is not the first instruction of the basic block 74 | body.Instructions.Remove(instruction); 75 | node.Instructions.RemoveAt(i); 76 | --i; 77 | } 78 | } 79 | } 80 | } 81 | 82 | body.UpdateVariables(); 83 | } 84 | 85 | public override DataFlowAnalysisResult>[] Analyze() 86 | { 87 | this.ComputeGen(); 88 | this.ComputeKill(); 89 | 90 | var result = base.Analyze(); 91 | 92 | this.result = result; 93 | this.GEN = null; 94 | this.KILL = null; 95 | 96 | return result; 97 | } 98 | 99 | protected override IDictionary InitialValue(CFGNode node) 100 | { 101 | return GEN[node.Id]; 102 | } 103 | 104 | protected override bool Compare(IDictionary left, IDictionary right) 105 | { 106 | return left.DictionaryEquals(right); 107 | } 108 | 109 | protected override IDictionary Join(IDictionary left, IDictionary right) 110 | { 111 | // result = intersection(left, right) 112 | var result = new Dictionary(); 113 | 114 | foreach (var copy in left) 115 | { 116 | var variable = copy.Key; 117 | var leftOperand = copy.Value; 118 | 119 | if (right.ContainsKey(variable)) 120 | { 121 | var rightOperand = right[variable]; 122 | 123 | if (leftOperand.Equals(rightOperand)) 124 | { 125 | result.Add(variable, leftOperand); 126 | } 127 | } 128 | } 129 | 130 | return result; 131 | } 132 | 133 | protected override IDictionary Flow(CFGNode node, IDictionary input) 134 | { 135 | var output = new Dictionary(input); 136 | var kill = KILL[node.Id]; 137 | var gen = GEN[node.Id]; 138 | 139 | foreach (var variable in kill) 140 | { 141 | this.RemoveCopiesWithVariable(output, variable); 142 | } 143 | 144 | output.AddRange(gen); 145 | return output; 146 | } 147 | 148 | private void ComputeGen() 149 | { 150 | GEN = new IDictionary[this.cfg.Nodes.Count]; 151 | 152 | foreach (var node in this.cfg.Nodes) 153 | { 154 | var gen = new Dictionary(); 155 | 156 | foreach (var instruction in node.Instructions) 157 | { 158 | this.Flow(instruction, gen); 159 | } 160 | 161 | GEN[node.Id] = gen; 162 | } 163 | } 164 | 165 | private void ComputeKill() 166 | { 167 | KILL = new ISet[this.cfg.Nodes.Count]; 168 | 169 | foreach (var node in this.cfg.Nodes) 170 | { 171 | var kill = new HashSet(); 172 | 173 | foreach (var instruction in node.Instructions) 174 | { 175 | kill.UnionWith(instruction.ModifiedVariables); 176 | } 177 | 178 | KILL[node.Id] = kill; 179 | } 180 | } 181 | 182 | private void RemoveCopiesWithVariable(IDictionary copies, IVariable variable) 183 | { 184 | var array = copies.ToArray(); 185 | 186 | foreach (var copy in array) 187 | { 188 | if (copy.Key == variable || 189 | copy.Value == variable) 190 | { 191 | copies.Remove(copy.Key); 192 | } 193 | } 194 | } 195 | 196 | private bool Flow(Instruction instruction, IDictionary copies) 197 | { 198 | IVariable left; 199 | IVariable right; 200 | 201 | var isCopy = instruction.IsCopy(out left, out right); 202 | 203 | if (isCopy) 204 | { 205 | // Only replace temporal variables 206 | if (right.IsTemporal() && 207 | copies.ContainsKey(right)) 208 | { 209 | right = copies[right]; 210 | } 211 | } 212 | 213 | foreach (var variable in instruction.ModifiedVariables) 214 | { 215 | this.RemoveCopiesWithVariable(copies, variable); 216 | } 217 | 218 | if (isCopy) 219 | { 220 | copies.Add(left, right); 221 | } 222 | 223 | var result = isCopy && left.IsTemporal(); 224 | return result; 225 | } 226 | } 227 | } 228 | -------------------------------------------------------------------------------- /Backend/Analysis/PointsToAnalysis.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Edgardo Zoppi. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. 2 | 3 | using Backend.ThreeAddressCode.Instructions; 4 | using Backend.ThreeAddressCode.Values; 5 | using Backend.Utils; 6 | using Microsoft.Cci; 7 | using System; 8 | using System.Collections.Generic; 9 | using System.Linq; 10 | using System.Text; 11 | 12 | namespace Backend.Analysis 13 | { 14 | // Unknown PTG nodes represent placeholders 15 | // (external objects that can be null or 16 | // stand for multiple objects). 17 | // Useful to model parameter values. 18 | public enum PTGNodeKind 19 | { 20 | Null, 21 | Object, 22 | Unknown 23 | } 24 | 25 | public class PTGNode 26 | { 27 | public int Id { get; private set; } 28 | public PTGNodeKind Kind { get; private set; } 29 | public uint Offset { get; set; } 30 | public ITypeReference Type { get; set; } 31 | public ISet Variables { get; private set; } 32 | public MapSet Sources { get; private set; } 33 | public MapSet Targets { get; private set; } 34 | 35 | public PTGNode(int id, PTGNodeKind kind = PTGNodeKind.Null) 36 | { 37 | this.Id = id; 38 | this.Kind = kind; 39 | this.Variables = new HashSet(); 40 | this.Sources = new MapSet(); 41 | this.Targets = new MapSet(); 42 | } 43 | 44 | public PTGNode(int id, ITypeReference type, uint offset = 0, PTGNodeKind kind = PTGNodeKind.Object) 45 | : this(id, kind) 46 | { 47 | this.Offset = offset; 48 | this.Type = type; 49 | } 50 | 51 | public bool SameEdges(PTGNode node) 52 | { 53 | if (node == null) throw new ArgumentNullException("node"); 54 | 55 | return this.Variables.SetEquals(node.Variables) && 56 | this.Sources.MapEquals(node.Sources) && 57 | this.Targets.MapEquals(node.Targets); 58 | } 59 | 60 | public override bool Equals(object obj) 61 | { 62 | if (object.ReferenceEquals(this, obj)) return true; 63 | var other = obj as PTGNode; 64 | 65 | return other != null && 66 | this.Id == other.Id && 67 | this.Kind == other.Kind && 68 | this.Offset == other.Offset && 69 | object.Equals(this.Type, other.Type); 70 | } 71 | 72 | public override int GetHashCode() 73 | { 74 | return this.Id.GetHashCode(); 75 | } 76 | 77 | public override string ToString() 78 | { 79 | string result; 80 | 81 | switch (this.Kind) 82 | { 83 | case PTGNodeKind.Null: 84 | result = "null"; 85 | break; 86 | 87 | default: 88 | var type = TypeHelper.GetTypeName(this.Type); 89 | result = string.Format("{0:X4}: {1}", this.Offset, type); 90 | break; 91 | } 92 | 93 | return result; 94 | } 95 | } 96 | 97 | public class PointsToGraph 98 | { 99 | private MapSet variables; 100 | private IDictionary nodes; 101 | 102 | public PTGNode Null { get; private set; } 103 | 104 | public PointsToGraph() 105 | { 106 | this.Null = new PTGNode(0, PTGNodeKind.Null); 107 | this.variables = new MapSet(); 108 | this.nodes = new Dictionary(); 109 | 110 | this.Add(this.Null); 111 | } 112 | 113 | public IEnumerable Variables 114 | { 115 | get { return this.variables.Keys; } 116 | } 117 | 118 | public IEnumerable Nodes 119 | { 120 | get { return nodes.Values; } 121 | } 122 | 123 | public PointsToGraph Clone() 124 | { 125 | var ptg = new PointsToGraph(); 126 | ptg.Union(this); 127 | return ptg; 128 | } 129 | 130 | public void Union(PointsToGraph ptg) 131 | { 132 | // add all new nodes 133 | foreach (var node in ptg.Nodes) 134 | { 135 | if (this.Contains(node)) continue; 136 | var clone = new PTGNode(node.Id, node.Type, node.Offset, node.Kind); 137 | 138 | nodes.Add(clone.Id, clone); 139 | } 140 | 141 | // add all variables 142 | foreach (var variable in ptg.Variables) 143 | { 144 | this.variables.Add(variable); 145 | } 146 | 147 | // add all edges 148 | foreach (var node in ptg.Nodes) 149 | { 150 | var clone = nodes[node.Id]; 151 | 152 | // add variable <---> node edges 153 | foreach (var variable in node.Variables) 154 | { 155 | clone.Variables.Add(variable); 156 | this.variables.Add(variable, clone); 157 | } 158 | 159 | // add source -field-> node edges 160 | foreach (var entry in node.Sources) 161 | foreach (var source in entry.Value) 162 | { 163 | var source_clone = nodes[source.Id]; 164 | 165 | clone.Sources.Add(entry.Key, source_clone); 166 | } 167 | 168 | // add node -field-> target edges 169 | foreach (var entry in node.Targets) 170 | foreach (var target in entry.Value) 171 | { 172 | var target_clone = nodes[target.Id]; 173 | 174 | clone.Targets.Add(entry.Key, target_clone); 175 | } 176 | } 177 | } 178 | 179 | public bool Contains(IVariable variable) 180 | { 181 | return this.variables.ContainsKey(variable); 182 | } 183 | 184 | public bool Contains(PTGNode node) 185 | { 186 | return this.ContainsNode(node.Id); 187 | } 188 | 189 | public bool ContainsNode(int id) 190 | { 191 | return nodes.ContainsKey(id); 192 | } 193 | 194 | public void Add(IVariable variable) 195 | { 196 | variables.Add(variable); 197 | } 198 | 199 | public void Add(PTGNode node) 200 | { 201 | nodes.Add(node.Id, node); 202 | } 203 | 204 | public PTGNode GetNode(int id) 205 | { 206 | return nodes[id]; 207 | } 208 | 209 | public ISet GetTargets(IVariable variable) 210 | { 211 | return variables[variable]; 212 | } 213 | 214 | public void Remove(IVariable variable) 215 | { 216 | this.RemoveEdges(variable); 217 | variables.Remove(variable); 218 | } 219 | 220 | public void PointsTo(IVariable variable, PTGNode target) 221 | { 222 | #if DEBUG 223 | if (!this.Contains(target)) 224 | throw new ArgumentException("Target node does not belong to this Points-to graph.", "target"); 225 | #endif 226 | 227 | target.Variables.Add(variable); 228 | this.variables.Add(variable, target); 229 | } 230 | 231 | public void PointsTo(PTGNode source, IFieldReference field, PTGNode target) 232 | { 233 | #if DEBUG 234 | if (!this.Contains(source)) 235 | throw new ArgumentException("Source node does not belong to this Points-to graph.", "source"); 236 | 237 | if (!this.Contains(target)) 238 | throw new ArgumentException("Target node does not belong to this Points-to graph.", "target"); 239 | #endif 240 | 241 | source.Targets.Add(field, target); 242 | target.Sources.Add(field, source); 243 | } 244 | 245 | public void RemoveEdges(IVariable variable) 246 | { 247 | var hasVariable = this.Contains(variable); 248 | if (!hasVariable) return; 249 | 250 | var targets = this.variables[variable]; 251 | 252 | foreach (var target in targets) 253 | { 254 | target.Variables.Remove(variable); 255 | } 256 | 257 | // If we uncomment the next line 258 | // the variable will be removed from 259 | // the graph, not only its edges 260 | //this.Roots.Remove(variable); 261 | 262 | // Remove only the edges of the variable, 263 | // but not the variable itself 264 | targets.Clear(); 265 | } 266 | 267 | public bool GraphEquals(object obj) 268 | { 269 | if (object.ReferenceEquals(this, obj)) return true; 270 | var other = obj as PointsToGraph; 271 | 272 | Func nodeEquals = (a, b) => a.Equals(b) && a.SameEdges(b); 273 | 274 | return other != null && 275 | this.variables.MapEquals(other.variables) && 276 | this.nodes.DictionaryEquals(other.nodes, nodeEquals); 277 | } 278 | } 279 | 280 | // May Points-To Analysis 281 | public class PointsToAnalysis : ForwardDataFlowAnalysis 282 | { 283 | private int nextPTGNodeId; 284 | private PointsToGraph initialGraph; 285 | private IDictionary nodeIdAtOffset; 286 | 287 | public PointsToAnalysis(ControlFlowGraph cfg) 288 | : base(cfg) 289 | { 290 | this.nextPTGNodeId = 1; 291 | this.nodeIdAtOffset = new Dictionary(); 292 | this.CreateInitialGraph(); 293 | } 294 | 295 | protected override PointsToGraph InitialValue(CFGNode node) 296 | { 297 | return this.initialGraph; 298 | } 299 | 300 | protected override bool Compare(PointsToGraph left, PointsToGraph right) 301 | { 302 | return left.GraphEquals(right); 303 | } 304 | 305 | protected override PointsToGraph Join(PointsToGraph left, PointsToGraph right) 306 | { 307 | var result = left.Clone(); 308 | result.Union(right); 309 | return result; 310 | } 311 | 312 | protected override PointsToGraph Flow(CFGNode node, PointsToGraph input) 313 | { 314 | var ptg = input.Clone(); 315 | 316 | foreach (var instruction in node.Instructions) 317 | { 318 | this.Flow(ptg, instruction); 319 | } 320 | 321 | return ptg; 322 | } 323 | 324 | private void Flow(PointsToGraph ptg, Instruction instruction) 325 | { 326 | var offset = instruction.Offset; 327 | 328 | if (instruction is CreateObjectInstruction) 329 | { 330 | var allocation = instruction as CreateObjectInstruction; 331 | this.ProcessObjectAllocation(ptg, offset, allocation.Result); 332 | } 333 | else if (instruction is CreateArrayInstruction) 334 | { 335 | var allocation = instruction as CreateArrayInstruction; 336 | this.ProcessArrayAllocation(ptg, offset, allocation.Result); 337 | } 338 | else if (instruction is LoadInstruction) 339 | { 340 | var load = instruction as LoadInstruction; 341 | 342 | if (load.Operand is Constant) 343 | { 344 | var constant = load.Operand as Constant; 345 | 346 | if (constant.Value == null) 347 | { 348 | this.ProcessNull(ptg, load.Result); 349 | } 350 | } 351 | if (load.Operand is IVariable) 352 | { 353 | var variable = load.Operand as IVariable; 354 | this.ProcessCopy(ptg, load.Result, variable); 355 | } 356 | else if (load.Operand is InstanceFieldAccess) 357 | { 358 | var access = load.Operand as InstanceFieldAccess; 359 | this.ProcessLoad(ptg, offset, load.Result, access); 360 | } 361 | } 362 | else if (instruction is StoreInstruction) 363 | { 364 | var store = instruction as StoreInstruction; 365 | 366 | if (store.Result is InstanceFieldAccess) 367 | { 368 | var access = store.Result as InstanceFieldAccess; 369 | this.ProcessStore(ptg, access, store.Operand); 370 | } 371 | } 372 | } 373 | 374 | private void CreateInitialGraph() 375 | { 376 | var ptg = new PointsToGraph(); 377 | var variables = cfg.GetVariables(); 378 | 379 | foreach (var variable in variables) 380 | { 381 | if (variable.Type.IsValueType) continue; 382 | 383 | if (variable.IsParameter) 384 | { 385 | var isThisParameter = variable.Name == "this"; 386 | var kind = isThisParameter ? PTGNodeKind.Object : PTGNodeKind.Unknown; 387 | var node = new PTGNode(nextPTGNodeId++, variable.Type, 0, kind); 388 | 389 | ptg.Add(node); 390 | ptg.PointsTo(variable, node); 391 | } 392 | else 393 | { 394 | ptg.Add(variable); 395 | } 396 | } 397 | 398 | this.initialGraph = ptg; 399 | } 400 | 401 | private void ProcessNull(PointsToGraph ptg, IVariable dst) 402 | { 403 | if (dst.Type.IsValueType) return; 404 | 405 | ptg.RemoveEdges(dst); 406 | ptg.PointsTo(dst, ptg.Null); 407 | } 408 | 409 | private void ProcessObjectAllocation(PointsToGraph ptg, uint offset, IVariable dst) 410 | { 411 | if (dst.Type.IsValueType) return; 412 | 413 | var node = this.GetNode(ptg, offset, dst.Type); 414 | 415 | ptg.RemoveEdges(dst); 416 | ptg.PointsTo(dst, node); 417 | } 418 | 419 | private void ProcessArrayAllocation(PointsToGraph ptg, uint offset, IVariable dst) 420 | { 421 | if (dst.Type.IsValueType) return; 422 | 423 | var node = this.GetNode(ptg, offset, dst.Type); 424 | 425 | ptg.RemoveEdges(dst); 426 | ptg.PointsTo(dst, node); 427 | } 428 | 429 | private void ProcessCopy(PointsToGraph ptg, IVariable dst, IVariable src) 430 | { 431 | if (dst.Type.IsValueType || src.Type.IsValueType) return; 432 | 433 | ptg.RemoveEdges(dst); 434 | var targets = ptg.GetTargets(src); 435 | 436 | foreach (var target in targets) 437 | { 438 | ptg.PointsTo(dst, target); 439 | } 440 | } 441 | 442 | private void ProcessLoad(PointsToGraph ptg, uint offset, IVariable dst, InstanceFieldAccess access) 443 | { 444 | if (dst.Type.IsValueType || access.Type.IsValueType) return; 445 | 446 | ptg.RemoveEdges(dst); 447 | var nodes = ptg.GetTargets(access.Instance); 448 | 449 | foreach (var node in nodes) 450 | { 451 | var hasField = node.Targets.ContainsKey(access.Field); 452 | 453 | if (!hasField) 454 | { 455 | var target = this.GetNode(ptg, offset, dst.Type, PTGNodeKind.Unknown); 456 | 457 | ptg.PointsTo(node, access.Field, target); 458 | } 459 | 460 | var targets = node.Targets[access.Field]; 461 | 462 | foreach (var target in targets) 463 | { 464 | ptg.PointsTo(dst, target); 465 | } 466 | } 467 | } 468 | 469 | private void ProcessStore(PointsToGraph ptg, InstanceFieldAccess access, IVariable src) 470 | { 471 | if (access.Type.IsValueType || src.Type.IsValueType) return; 472 | 473 | var nodes = ptg.GetTargets(access.Instance); 474 | var targets = ptg.GetTargets(src); 475 | 476 | foreach (var node in nodes) 477 | foreach (var target in targets) 478 | { 479 | ptg.PointsTo(node, access.Field, target); 480 | } 481 | } 482 | 483 | private PTGNode GetNode(PointsToGraph ptg, uint offset, ITypeReference type, PTGNodeKind kind = PTGNodeKind.Object) 484 | { 485 | PTGNode node; 486 | 487 | if (nodeIdAtOffset.ContainsKey(offset)) 488 | { 489 | var nodeId = nodeIdAtOffset[offset]; 490 | node = ptg.GetNode(nodeId); 491 | } 492 | else 493 | { 494 | var nodeId = nextPTGNodeId++; 495 | node = new PTGNode(nodeId, type, offset, kind); 496 | 497 | ptg.Add(node); 498 | nodeIdAtOffset.Add(offset, nodeId); 499 | } 500 | 501 | return node; 502 | } 503 | } 504 | } 505 | -------------------------------------------------------------------------------- /Backend/Analysis/ReachingDefinitionsAnalysis.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Edgardo Zoppi. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. 2 | 3 | using Backend.ThreeAddressCode; 4 | using Backend.Utils; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using System.Text; 9 | using Backend.ThreeAddressCode.Instructions; 10 | using Backend.ThreeAddressCode.Values; 11 | 12 | namespace Backend.Analysis 13 | { 14 | public class ReachingDefinitionsAnalysis : ForwardDataFlowAnalysis> 15 | { 16 | private DefinitionInstruction[] definitions; 17 | private IDictionary> variable_definitions; 18 | private DataFlowAnalysisResult>[] result; 19 | private MapList def_use; 20 | private MapList use_def; 21 | private Subset[] GEN; 22 | private Subset[] KILL; 23 | 24 | public ReachingDefinitionsAnalysis(ControlFlowGraph cfg) 25 | : base(cfg) 26 | { 27 | } 28 | 29 | public MapList DefinitionUses 30 | { 31 | get { return def_use; } 32 | } 33 | 34 | public MapList UseDefinitions 35 | { 36 | get { return use_def; } 37 | } 38 | 39 | public void ComputeDefUseAndUseDefChains() 40 | { 41 | if (this.result == null) throw new InvalidOperationException("Analysis result not available."); 42 | 43 | this.def_use = new MapList(); 44 | this.use_def = new MapList(); 45 | 46 | foreach (var node in this.cfg.Nodes) 47 | { 48 | var input = new HashSet(); 49 | var node_result = this.result[node.Id]; 50 | 51 | if (node_result.Input != null) 52 | { 53 | node_result.Input.ToSet(input); 54 | } 55 | 56 | var definitions = input.ToMapSet(def => def.Result); 57 | 58 | foreach (var instruction in node.Instructions) 59 | { 60 | // use-def 61 | foreach (var variable in instruction.UsedVariables) 62 | { 63 | if (definitions.ContainsKey(variable)) 64 | { 65 | var var_defs = definitions[variable]; 66 | 67 | foreach (var definition in var_defs) 68 | { 69 | def_use.Add(definition, instruction); 70 | use_def.Add(instruction, definition); 71 | } 72 | } 73 | else 74 | { 75 | // Add all uses, even those with no reaching definitions. 76 | use_def.Add(instruction); 77 | } 78 | } 79 | 80 | // def-use 81 | if (instruction is DefinitionInstruction) 82 | { 83 | var definition = instruction as DefinitionInstruction; 84 | 85 | if (definition.HasResult) 86 | { 87 | var variable = definition.Result; 88 | 89 | definitions.Remove(variable); 90 | definitions.Add(variable, definition); 91 | 92 | // Add all definitions, even those with no uses. 93 | def_use.Add(definition); 94 | } 95 | } 96 | } 97 | } 98 | } 99 | 100 | public override DataFlowAnalysisResult>[] Analyze() 101 | { 102 | this.ComputeDefinitions(); 103 | this.ComputeGen(); 104 | this.ComputeKill(); 105 | 106 | var result = base.Analyze(); 107 | 108 | this.result = result; 109 | this.definitions = null; 110 | this.variable_definitions = null; 111 | this.GEN = null; 112 | this.KILL = null; 113 | 114 | return result; 115 | } 116 | 117 | protected override Subset InitialValue(CFGNode node) 118 | { 119 | return GEN[node.Id]; 120 | } 121 | 122 | protected override bool Compare(Subset left, Subset right) 123 | { 124 | return left.Equals(right); 125 | } 126 | 127 | protected override Subset Join(Subset left, Subset right) 128 | { 129 | var result = left.Clone(); 130 | result.Union(right); 131 | return result; 132 | } 133 | 134 | protected override Subset Flow(CFGNode node, Subset input) 135 | { 136 | var output = input.Clone(); 137 | var kill = KILL[node.Id]; 138 | var gen = GEN[node.Id]; 139 | 140 | output.Except(kill); 141 | output.Union(gen); 142 | return output; 143 | } 144 | 145 | private void ComputeDefinitions() 146 | { 147 | var result = new List(); 148 | 149 | foreach (var node in this.cfg.Nodes) 150 | { 151 | foreach (var instruction in node.Instructions) 152 | { 153 | if (instruction is DefinitionInstruction) 154 | { 155 | var definition = instruction as DefinitionInstruction; 156 | 157 | if (definition.HasResult) 158 | { 159 | result.Add(definition); 160 | } 161 | } 162 | } 163 | } 164 | 165 | this.definitions = result.ToArray(); 166 | this.variable_definitions = new Dictionary>(); 167 | 168 | for (var i = 0; i < this.definitions.Length; ++i) 169 | { 170 | var definition = this.definitions[i]; 171 | Subset defs = null; 172 | 173 | if (variable_definitions.ContainsKey(definition.Result)) 174 | { 175 | defs = variable_definitions[definition.Result]; 176 | } 177 | else 178 | { 179 | defs = this.definitions.ToEmptySubset(); 180 | variable_definitions[definition.Result] = defs; 181 | } 182 | 183 | defs.Add(i); 184 | } 185 | } 186 | 187 | private void ComputeGen() 188 | { 189 | GEN = new Subset[this.cfg.Nodes.Count]; 190 | var index = 0; 191 | 192 | foreach (var node in this.cfg.Nodes) 193 | { 194 | var defined = new Dictionary(); 195 | 196 | foreach (var instruction in node.Instructions) 197 | { 198 | if (instruction is DefinitionInstruction) 199 | { 200 | var definition = instruction as DefinitionInstruction; 201 | 202 | if (definition.HasResult) 203 | { 204 | defined[definition.Result] = index; 205 | index++; 206 | } 207 | } 208 | } 209 | 210 | // We only add to gen those definitions of node 211 | // that reach the end of the basic block 212 | var gen = this.definitions.ToEmptySubset(); 213 | 214 | foreach (var def in defined.Values) 215 | { 216 | gen.Add(def); 217 | } 218 | 219 | GEN[node.Id] = gen; 220 | } 221 | } 222 | 223 | private void ComputeKill() 224 | { 225 | KILL = new Subset[this.cfg.Nodes.Count]; 226 | 227 | foreach (var node in this.cfg.Nodes) 228 | { 229 | // We add to kill all definitions of the variables defined at node 230 | var kill = this.definitions.ToEmptySubset(); 231 | 232 | foreach (var instruction in node.Instructions) 233 | { 234 | if (instruction is DefinitionInstruction) 235 | { 236 | var definition = instruction as DefinitionInstruction; 237 | 238 | if (definition.HasResult) 239 | { 240 | var defs = this.variable_definitions[definition.Result]; 241 | kill.Union(defs); 242 | } 243 | } 244 | } 245 | 246 | KILL[node.Id] = kill; 247 | } 248 | } 249 | } 250 | } 251 | -------------------------------------------------------------------------------- /Backend/Analysis/StaticSingleAssignmentAnalysis.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Edgardo Zoppi. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. 2 | 3 | using Backend.ThreeAddressCode; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Text; 8 | using Backend.ThreeAddressCode.Values; 9 | using Backend.ThreeAddressCode.Instructions; 10 | 11 | namespace Backend.Analysis 12 | { 13 | public class StaticSingleAssignmentAnalysis 14 | { 15 | private MethodBody method; 16 | private ControlFlowGraph cfg; 17 | private IDictionary> phi_instructions; 18 | 19 | public StaticSingleAssignmentAnalysis(MethodBody method, ControlFlowGraph cfg) 20 | { 21 | this.method = method; 22 | this.cfg = cfg; 23 | this.phi_instructions = new Dictionary>(); 24 | } 25 | 26 | public void Transform() 27 | { 28 | //ControlFlowGraph.ComputeDominators(cfg); 29 | //ControlFlowGraph.ComputeDominatorTree(cfg); 30 | //ControlFlowGraph.ComputeDominanceFrontiers(cfg); 31 | 32 | //this.method.UpdateVariables(); 33 | 34 | this.InsertPhiInstructions(); 35 | this.RenameVariables(); 36 | 37 | //this.method.UpdateVariables(); 38 | } 39 | 40 | private void InsertPhiInstructions() 41 | { 42 | var defining_nodes = new Dictionary>(); 43 | 44 | foreach (var node in cfg.Nodes) 45 | { 46 | foreach (var instruction in node.Instructions) 47 | { 48 | if (instruction is DefinitionInstruction) 49 | { 50 | var definition = instruction as DefinitionInstruction; 51 | 52 | if (definition.HasResult) 53 | { 54 | ISet nodes; 55 | 56 | if (defining_nodes.ContainsKey(definition.Result)) 57 | { 58 | nodes = defining_nodes[definition.Result]; 59 | } 60 | else 61 | { 62 | nodes = new HashSet(); 63 | defining_nodes.Add(definition.Result, nodes); 64 | } 65 | 66 | nodes.Add(node); 67 | } 68 | } 69 | } 70 | } 71 | 72 | foreach (var entry in defining_nodes) 73 | { 74 | var variable = entry.Key; 75 | var nodes = new Stack(entry.Value); 76 | 77 | while (nodes.Count > 0) 78 | { 79 | var current = nodes.Pop(); 80 | 81 | foreach (var node in current.DominanceFrontier) 82 | { 83 | if (phi_instructions.ContainsKey(node) && phi_instructions[node].ContainsKey(variable)) continue; 84 | IDictionary node_phi_instructions; 85 | 86 | if (phi_instructions.ContainsKey(node)) 87 | { 88 | node_phi_instructions = phi_instructions[node]; 89 | } 90 | else 91 | { 92 | node_phi_instructions = new Dictionary(); 93 | phi_instructions.Add(node, node_phi_instructions); 94 | } 95 | 96 | var phi = new PhiInstruction(0, variable); 97 | 98 | // TODO: Also insert phi instructions into method's body instructions collection. 99 | 100 | node.Instructions.Insert(0, phi); 101 | node_phi_instructions.Add(variable, phi); 102 | 103 | if (!defining_nodes[variable].Contains(node) && !nodes.Contains(node)) 104 | { 105 | nodes.Push(node); 106 | } 107 | } 108 | } 109 | } 110 | } 111 | 112 | private void RenameVariables() 113 | { 114 | var derived_variables = new Dictionary>(); 115 | var indices = new Dictionary(); 116 | 117 | foreach (var variable in method.Variables) 118 | { 119 | var derived = new DerivedVariable(variable, 0u); 120 | var stack = new Stack(); 121 | 122 | stack.Push(derived); 123 | derived_variables.Add(variable, stack); 124 | indices.Add(variable, 1u); 125 | } 126 | 127 | this.RenameParameters(derived_variables); 128 | this.RenameVariables(cfg.Entry, derived_variables, indices); 129 | } 130 | 131 | private void RenameParameters(Dictionary> derived_variables) 132 | { 133 | for (var i = 0; i < this.method.Parameters.Count; ++i) 134 | { 135 | var parameter = this.method.Parameters[i]; 136 | var stack = derived_variables[parameter]; 137 | var derived = stack.Peek(); 138 | 139 | this.method.Parameters[i] = derived; 140 | } 141 | } 142 | 143 | private void RenameVariables(CFGNode node, IDictionary> derived_variables, Dictionary indices) 144 | { 145 | foreach (var instruction in node.Instructions) 146 | { 147 | DerivedVariable result_derived = null; 148 | 149 | if (instruction is DefinitionInstruction) 150 | { 151 | var definition = instruction as DefinitionInstruction; 152 | 153 | //if (definition.HasResult && indices.ContainsKey(definition.Result)) 154 | if (definition.HasResult) 155 | { 156 | var result = definition.Result; 157 | var index = indices[result]; 158 | 159 | result_derived = new DerivedVariable(result, index); 160 | definition.Result = result_derived; 161 | } 162 | } 163 | 164 | foreach (var variable in instruction.UsedVariables) 165 | { 166 | // When the instruction is a phi, its arguments (used variables) 167 | // are already derived variables, so there is no entry in 168 | // derived_variables dictionary for them. 169 | if (!derived_variables.ContainsKey(variable)) continue; 170 | 171 | var stack = derived_variables[variable]; 172 | var derived = stack.Peek(); 173 | instruction.Replace(variable, derived); 174 | } 175 | 176 | if (result_derived != null) 177 | { 178 | var result = result_derived.Original; 179 | var index = result_derived.Index; 180 | var result_stack = derived_variables[result]; 181 | 182 | result_stack.Push(result_derived); 183 | indices[result] = index + 1; 184 | } 185 | } 186 | 187 | foreach (var succ in node.Successors) 188 | { 189 | if (!phi_instructions.ContainsKey(succ)) continue; 190 | var node_phi_instructions = phi_instructions[succ]; 191 | 192 | foreach (var entry in node_phi_instructions) 193 | { 194 | var variable = entry.Key; 195 | var phi = entry.Value; 196 | var stack = derived_variables[variable]; 197 | var derived = stack.Peek(); 198 | 199 | phi.Arguments.Add(derived); 200 | } 201 | } 202 | 203 | foreach (var child in node.ImmediateDominated) 204 | { 205 | this.RenameVariables(child, derived_variables, indices); 206 | } 207 | 208 | foreach (var instruction in node.Instructions) 209 | { 210 | if (instruction is DefinitionInstruction) 211 | { 212 | var definition = instruction as DefinitionInstruction; 213 | 214 | if (definition.HasResult) 215 | { 216 | var derived = definition.Result as DerivedVariable; 217 | var result = derived.Original; 218 | var stack = derived_variables[result]; 219 | 220 | stack.Pop(); 221 | } 222 | } 223 | } 224 | } 225 | } 226 | } 227 | -------------------------------------------------------------------------------- /Backend/Analysis/SymbolicAnalysis.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Edgardo Zoppi. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. 2 | 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | 8 | using Backend.ThreeAddressCode; 9 | using Backend.Utils; 10 | using Backend.ThreeAddressCode.Values; 11 | using Backend.ThreeAddressCode.Expressions; 12 | using Backend.ThreeAddressCode.Instructions; 13 | 14 | namespace Backend.Analysis 15 | { 16 | [Obsolete("The analysis implementation could have some bugs!")] 17 | public class SymbolicAnalysis : ForwardDataFlowAnalysis> 18 | { 19 | private DataFlowAnalysisResult>[] result; 20 | private IDictionary[] GEN; 21 | private ISet[] KILL; 22 | 23 | public SymbolicAnalysis(ControlFlowGraph cfg) 24 | : base(cfg) 25 | { 26 | } 27 | 28 | public override DataFlowAnalysisResult>[] Analyze() 29 | { 30 | this.ComputeGen(); 31 | this.ComputeKill(); 32 | 33 | var result = base.Analyze(); 34 | 35 | this.result = result; 36 | this.GEN = null; 37 | this.KILL = null; 38 | 39 | return result; 40 | } 41 | 42 | public DataFlowAnalysisResult> this[CFGNode node] 43 | { 44 | get { return this.result[node.Id]; } 45 | } 46 | 47 | protected override IDictionary InitialValue(CFGNode node) 48 | { 49 | return GEN[node.Id]; 50 | } 51 | 52 | protected override bool Compare(IDictionary left, IDictionary right) 53 | { 54 | return left.DictionaryEquals(right); 55 | } 56 | 57 | protected override IDictionary Join(IDictionary left, IDictionary right) 58 | { 59 | var result = new Dictionary(left); 60 | 61 | foreach (var equality in right) 62 | { 63 | var variable = equality.Key; 64 | var rightExpr = equality.Value; 65 | 66 | if (left.ContainsKey(variable)) 67 | { 68 | var leftExpr = left[variable]; 69 | 70 | if (!leftExpr.Equals(rightExpr)) 71 | { 72 | result[variable] = UnknownValue.Value; 73 | } 74 | } 75 | else 76 | { 77 | result[variable] = rightExpr; 78 | } 79 | } 80 | 81 | return result; 82 | } 83 | 84 | protected override IDictionary Flow(CFGNode node, IDictionary input) 85 | { 86 | IDictionary result; 87 | 88 | if (input == null) 89 | { 90 | result = new Dictionary(); 91 | } 92 | else 93 | { 94 | result = new Dictionary(input); 95 | } 96 | 97 | foreach (var instruction in node.Instructions) 98 | { 99 | var equality = this.Flow(instruction, result); 100 | 101 | foreach (var variable in instruction.ModifiedVariables) 102 | { 103 | this.RemoveEqualitiesWithVariable(result, variable); 104 | } 105 | 106 | if (equality.HasValue) 107 | { 108 | result.Add(equality.Value); 109 | } 110 | } 111 | 112 | return result; 113 | } 114 | 115 | private void ComputeGen() 116 | { 117 | GEN = new IDictionary[this.cfg.Nodes.Count]; 118 | 119 | foreach (var node in this.cfg.Nodes) 120 | { 121 | var gen = this.Flow(node, null); 122 | GEN[node.Id] = gen; 123 | } 124 | } 125 | 126 | private void ComputeKill() 127 | { 128 | KILL = new ISet[this.cfg.Nodes.Count]; 129 | 130 | foreach (var node in this.cfg.Nodes) 131 | { 132 | var kill = new HashSet(); 133 | 134 | foreach (var instruction in node.Instructions) 135 | { 136 | kill.UnionWith(instruction.ModifiedVariables); 137 | } 138 | 139 | KILL[node.Id] = kill; 140 | } 141 | } 142 | 143 | private void RemoveEqualitiesWithVariable(IDictionary equalities, IVariable variable) 144 | { 145 | var array = equalities.ToArray(); 146 | 147 | foreach (var equality in array) 148 | { 149 | if (equality.Key == variable || 150 | equality.Value == variable) 151 | { 152 | equalities.Remove(equality); 153 | } 154 | } 155 | } 156 | 157 | private KeyValuePair? Flow(Instruction instruction, IDictionary equalities) 158 | { 159 | KeyValuePair? result = null; 160 | 161 | if (instruction is LoadInstruction) 162 | { 163 | var assignment = instruction as LoadInstruction; 164 | var expr = assignment.Operand.ToExpression().ReplaceVariables(equalities); 165 | result = new KeyValuePair(assignment.Result, expr); 166 | } 167 | //else if (instruction is PhiInstruction) 168 | //{ 169 | // var phi = instruction as PhiInstruction; 170 | // var arguments = phi.Arguments.Skip(1); 171 | // IExpression expr = phi.Arguments.First(); 172 | 173 | // foreach (var arg in arguments) 174 | // { 175 | // expr = new BinaryExpression(expr, BinaryOperation.Or, arg); 176 | // } 177 | 178 | // result = new KeyValuePair(phi.Result, expr); 179 | //} 180 | 181 | return result; 182 | } 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /Backend/Analysis/TypeInferenceAnalysis.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Edgardo Zoppi. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. 2 | 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using Backend.ThreeAddressCode.Instructions; 8 | using Backend.Visitors; 9 | using Microsoft.Cci; 10 | 11 | namespace Backend.Analysis 12 | { 13 | public class TypeInferenceAnalysis 14 | { 15 | #region class TypeInferencer 16 | 17 | private class TypeInferencer : InstructionVisitor 18 | { 19 | public override void Visit(LocalAllocationInstruction instruction) 20 | { 21 | instruction.TargetAddress.Type = Types.Instance.NativePointerType; 22 | } 23 | 24 | public override void Visit(SizeofInstruction instruction) 25 | { 26 | instruction.Result.Type = Types.Instance.SizeofType; 27 | } 28 | 29 | public override void Visit(CreateArrayInstruction instruction) 30 | { 31 | instruction.Result.Type = Types.Instance.ArrayType(instruction.ElementType, instruction.Rank); 32 | } 33 | 34 | public override void Visit(CatchInstruction instruction) 35 | { 36 | instruction.Result.Type = instruction.ExceptionType; 37 | } 38 | 39 | public override void Visit(CreateObjectInstruction instruction) 40 | { 41 | instruction.Result.Type = instruction.Constructor.ContainingType; 42 | } 43 | 44 | public override void Visit(MethodCallInstruction instruction) 45 | { 46 | if (instruction.HasResult) 47 | { 48 | instruction.Result.Type = instruction.Method.Type; 49 | } 50 | } 51 | 52 | public override void Visit(IndirectMethodCallInstruction instruction) 53 | { 54 | if (instruction.HasResult) 55 | { 56 | instruction.Result.Type = instruction.Function.Type; 57 | } 58 | } 59 | 60 | public override void Visit(LoadInstruction instruction) 61 | { 62 | instruction.Result.Type = instruction.Operand.Type; 63 | } 64 | 65 | public override void Visit(LoadTokenInstruction instruction) 66 | { 67 | instruction.Result.Type = Types.Instance.TokenType(instruction.Token); 68 | } 69 | 70 | public override void Visit(StoreInstruction instruction) 71 | { 72 | // Nothing to do here, for debugging purposes only 73 | } 74 | 75 | public override void Visit(UnaryInstruction instruction) 76 | { 77 | instruction.Result.Type = instruction.Operand.Type; 78 | } 79 | 80 | public override void Visit(ConvertInstruction instruction) 81 | { 82 | var type = instruction.Operand.Type; 83 | 84 | switch (instruction.Operation) 85 | { 86 | case ConvertOperation.Cast: 87 | case ConvertOperation.Box: 88 | case ConvertOperation.Unbox: 89 | // ConversionType is the data type of the result 90 | type = instruction.ConversionType; 91 | break; 92 | 93 | case ConvertOperation.UnboxPtr: 94 | // Pointer to ConversionType is the data type of the result 95 | type = Types.Instance.PointerType(instruction.ConversionType); 96 | break; 97 | } 98 | 99 | instruction.Result.Type = type; 100 | } 101 | 102 | public override void Visit(PhiInstruction instruction) 103 | { 104 | var type = instruction.Arguments.First().Type; 105 | var arguments = instruction.Arguments.Skip(1); 106 | 107 | foreach (var argument in arguments) 108 | { 109 | type = TypeHelper.MergedType(type, argument.Type); 110 | } 111 | 112 | instruction.Result.Type = type; 113 | } 114 | 115 | public override void Visit(BinaryInstruction instruction) 116 | { 117 | var left = instruction.LeftOperand.Type; 118 | var right = instruction.RightOperand.Type; 119 | var unsigned = instruction.UnsignedOperands; 120 | 121 | switch (instruction.Operation) 122 | { 123 | case BinaryOperation.Add: 124 | case BinaryOperation.Div: 125 | case BinaryOperation.Mul: 126 | case BinaryOperation.Rem: 127 | case BinaryOperation.Sub: 128 | instruction.Result.Type = Types.Instance.BinaryNumericOperationType(left, right, unsigned); 129 | break; 130 | 131 | case BinaryOperation.And: 132 | case BinaryOperation.Or: 133 | case BinaryOperation.Xor: 134 | instruction.Result.Type = Types.Instance.BinaryLogicalOperationType(left, right); 135 | break; 136 | 137 | case BinaryOperation.Shl: 138 | case BinaryOperation.Shr: 139 | instruction.Result.Type = left; 140 | break; 141 | 142 | case BinaryOperation.Eq: 143 | case BinaryOperation.Gt: 144 | case BinaryOperation.Lt: 145 | instruction.Result.Type = Types.Instance.PlatformType.SystemBoolean; 146 | break; 147 | } 148 | } 149 | } 150 | 151 | #endregion 152 | 153 | private ControlFlowGraph cfg; 154 | 155 | public TypeInferenceAnalysis(ControlFlowGraph cfg) 156 | { 157 | this.cfg = cfg; 158 | } 159 | 160 | public void Analyze() 161 | { 162 | var inferer = new TypeInferencer(); 163 | var sorted_nodes = cfg.ForwardOrder; 164 | 165 | // TODO: Propagate types over the CFG until a fixpoint is reached (i.e. when types do not change) 166 | 167 | for (var i = 0; i < sorted_nodes.Length; ++i) 168 | { 169 | var node = sorted_nodes[i]; 170 | inferer.Visit(node); 171 | } 172 | } 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /Backend/Analysis/WebAnalysis.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Edgardo Zoppi. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. 2 | 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using Backend.ThreeAddressCode.Instructions; 8 | using Backend.ThreeAddressCode.Values; 9 | using Backend.Utils; 10 | 11 | namespace Backend.Analysis 12 | { 13 | public class Web 14 | { 15 | public IVariable Variable { get; private set; } 16 | public ISet Definitions { get; private set; } 17 | public ISet Uses { get; private set; } 18 | 19 | public Web(IVariable variable) 20 | { 21 | this.Variable = variable; 22 | this.Definitions = new HashSet(); 23 | this.Uses = new HashSet(); 24 | } 25 | 26 | public void Rename(IVariable variable) 27 | { 28 | var oldvar = this.Variable; 29 | var newvar = variable; 30 | 31 | foreach (var definition in this.Definitions) 32 | { 33 | definition.Result = newvar; 34 | } 35 | 36 | foreach (var instruction in this.Uses) 37 | { 38 | instruction.Replace(oldvar, newvar); 39 | } 40 | 41 | this.Variable = variable; 42 | } 43 | 44 | public override string ToString() 45 | { 46 | return this.Variable.ToString(); 47 | } 48 | } 49 | 50 | public class WebAnalysis 51 | { 52 | private ControlFlowGraph cfg; 53 | private IList result; 54 | 55 | public WebAnalysis(ControlFlowGraph cfg) 56 | { 57 | this.cfg = cfg; 58 | } 59 | 60 | public IList Result 61 | { 62 | get { return this.result; } 63 | } 64 | 65 | public IList Analyze() 66 | { 67 | var analysis = new ReachingDefinitionsAnalysis(cfg); 68 | analysis.Analyze(); 69 | analysis.ComputeDefUseAndUseDefChains(); 70 | 71 | var result = this.ComputeWebs(analysis.DefinitionUses, analysis.UseDefinitions); 72 | this.result = result; 73 | return result; 74 | } 75 | 76 | public void Transform() 77 | { 78 | if (this.result == null) throw new InvalidOperationException("Analysis result not available."); 79 | var index = 0u; 80 | 81 | foreach (var web in this.result) 82 | { 83 | // Do not rename local variables, only rename temporal variables. 84 | if (web.Variable.IsTemporal()) 85 | { 86 | var variable = new TemporalVariable("$r", index); 87 | web.Rename(variable); 88 | index++; 89 | } 90 | } 91 | } 92 | 93 | private IList ComputeWebs(MapList def_use, MapList use_def) 94 | { 95 | var result = new List(); 96 | var definitions = def_use.Keys.ToList(); 97 | 98 | while (definitions.Count > 0) 99 | { 100 | var def = definitions.First(); 101 | var variable = def.Result; 102 | var web = new Web(variable); 103 | var pending_defs = new HashSet(); 104 | var pending_uses = new HashSet(); 105 | 106 | result.Add(web); 107 | pending_defs.Add(def); 108 | 109 | while (pending_defs.Count > 0) 110 | { 111 | while (pending_defs.Count > 0) 112 | { 113 | var definition = pending_defs.First(); 114 | pending_defs.Remove(definition); 115 | 116 | web.Definitions.Add(definition); 117 | definitions.Remove(definition); 118 | 119 | var uses = def_use[definition]; 120 | var new_uses = uses.Except(web.Uses); 121 | pending_uses.UnionWith(new_uses); 122 | } 123 | 124 | while (pending_uses.Count > 0) 125 | { 126 | var instruction = pending_uses.First(); 127 | pending_uses.Remove(instruction); 128 | 129 | web.Uses.Add(instruction); 130 | 131 | var defs = use_def[instruction]; 132 | var var_defs = defs.Where(d => d.Result.Equals(variable)); 133 | var new_defs = var_defs.Except(web.Definitions); 134 | pending_defs.UnionWith(new_defs); 135 | } 136 | } 137 | } 138 | 139 | return result; 140 | } 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /Backend/Backend.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | 8.0.30703 7 | 2.0 8 | {45C7B613-E32D-43E8-8030-932D509602EB} 9 | Library 10 | Properties 11 | Backend 12 | Backend 13 | v4.0 14 | 512 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | pdbonly 27 | true 28 | bin\Release\ 29 | TRACE 30 | prompt 31 | 4 32 | 33 | 34 | 35 | ..\Dependencies\Microsoft.Cci.ILGenerator.dll 36 | 37 | 38 | ..\Dependencies\Microsoft.Cci.MetadataHelper.dll 39 | 40 | 41 | ..\Dependencies\Microsoft.Cci.MetadataModel.dll 42 | 43 | 44 | ..\Dependencies\Microsoft.Cci.MutableMetadataModel.dll 45 | 46 | 47 | ..\Dependencies\Microsoft.Cci.PdbReader.dll 48 | 49 | 50 | ..\Dependencies\Microsoft.Cci.PdbWriter.dll 51 | 52 | 53 | ..\Dependencies\Microsoft.Cci.PeReader.dll 54 | 55 | 56 | ..\Dependencies\Microsoft.Cci.PeWriter.dll 57 | 58 | 59 | ..\Dependencies\Microsoft.Cci.SourceModel.dll 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 109 | -------------------------------------------------------------------------------- /Backend/MethodBody.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Edgardo Zoppi. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. 2 | 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using Microsoft.Cci; 8 | using Backend.ThreeAddressCode; 9 | using Backend.ThreeAddressCode.Instructions; 10 | using Backend.ThreeAddressCode.Values; 11 | using Backend.Visitors; 12 | 13 | namespace Backend 14 | { 15 | public class MethodBody : IInstructionContainer 16 | { 17 | public IMethodDefinition MethodDefinition { get; private set; } 18 | public IList ProtectedBlocks { get; private set; } 19 | public IList Instructions { get; private set; } 20 | public IList Parameters { get; private set; } 21 | public ISet Variables { get; private set; } 22 | 23 | public MethodBody(IMethodDefinition methodDefinition) 24 | { 25 | this.MethodDefinition = methodDefinition; 26 | this.ProtectedBlocks = new List(); 27 | this.Instructions = new List(); 28 | this.Parameters = new List(); 29 | this.Variables = new HashSet(); 30 | } 31 | 32 | public void UpdateVariables() 33 | { 34 | this.Variables.Clear(); 35 | this.Variables.UnionWith(this.Parameters); 36 | 37 | // TODO: SSA is not inserting phi instructions into method's body instructions collection. 38 | foreach (var instruction in this.Instructions) 39 | { 40 | this.Variables.UnionWith(instruction.Variables); 41 | } 42 | } 43 | 44 | public override string ToString() 45 | { 46 | var result = new StringBuilder(); 47 | var header = MemberHelper.GetMethodSignature(this.MethodDefinition, NameFormattingOptions.Signature | NameFormattingOptions.ParameterName); 48 | 49 | result.AppendLine(header); 50 | 51 | foreach (var variable in this.Variables) 52 | { 53 | var type = "unknown"; 54 | 55 | if (variable.Type != null) 56 | { 57 | type = TypeHelper.GetTypeName(variable.Type); 58 | } 59 | 60 | result.AppendFormat(" {0} {1};", type, variable.Name); 61 | result.AppendLine(); 62 | } 63 | 64 | result.AppendLine(); 65 | 66 | foreach (var instruction in this.Instructions) 67 | { 68 | result.Append(" "); 69 | result.Append(instruction); 70 | result.AppendLine(); 71 | } 72 | 73 | foreach (var handler in this.ProtectedBlocks) 74 | { 75 | result.AppendLine(); 76 | result.Append(handler); 77 | } 78 | 79 | return result.ToString(); 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /Backend/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Edgardo Zoppi. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. 2 | 3 | using System.Reflection; 4 | using System.Runtime.CompilerServices; 5 | using System.Runtime.InteropServices; 6 | 7 | // General Information about an assembly is controlled through the following 8 | // set of attributes. Change these attribute values to modify the information 9 | // associated with an assembly. 10 | [assembly: AssemblyTitle("Backend")] 11 | [assembly: AssemblyDescription("")] 12 | [assembly: AssemblyConfiguration("")] 13 | [assembly: AssemblyCompany("")] 14 | [assembly: AssemblyProduct("Backend")] 15 | [assembly: AssemblyCopyright("Copyright © Edgardo Zoppi")] 16 | [assembly: AssemblyTrademark("")] 17 | [assembly: AssemblyCulture("")] 18 | 19 | // Setting ComVisible to false makes the types in this assembly not visible 20 | // to COM components. If you need to access a type in this assembly from 21 | // COM, set the ComVisible attribute to true on that type. 22 | [assembly: ComVisible(false)] 23 | 24 | // The following GUID is for the ID of the typelib if this project is exposed to COM 25 | [assembly: Guid("a93cff0b-bbe5-4038-b650-e759403509e5")] 26 | 27 | // Version information for an assembly consists of the following four values: 28 | // 29 | // Major Version 30 | // Minor Version 31 | // Build Number 32 | // Revision 33 | // 34 | // You can specify all the values or you can default the Build and Revision Numbers 35 | // by using the '*' as shown below: 36 | // [assembly: AssemblyVersion("1.0.*")] 37 | [assembly: AssemblyVersion("1.0.0.0")] 38 | [assembly: AssemblyFileVersion("1.0.0.0")] 39 | -------------------------------------------------------------------------------- /Backend/Serialization/DGMLSerializer.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Edgardo Zoppi. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. 2 | 3 | using System; 4 | using System.Collections.Generic; 5 | using System.IO; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Xml; 9 | using Backend.Analysis; 10 | using Microsoft.Cci; 11 | 12 | namespace Backend.Serialization 13 | { 14 | public static class DGMLSerializer 15 | { 16 | #region Control-Flow Graph 17 | 18 | public static string Serialize(ControlFlowGraph cfg) 19 | { 20 | using (var stringWriter = new StringWriter()) 21 | using (var xmlWriter = new XmlTextWriter(stringWriter)) 22 | { 23 | xmlWriter.Formatting = Formatting.Indented; 24 | xmlWriter.WriteStartElement("DirectedGraph"); 25 | xmlWriter.WriteAttributeString("xmlns", "http://schemas.microsoft.com/vs/2009/dgml"); 26 | xmlWriter.WriteStartElement("Nodes"); 27 | 28 | foreach (var node in cfg.Nodes) 29 | { 30 | var nodeId = Convert.ToString(node.Id); 31 | var label = DGMLSerializer.Serialize(node); 32 | 33 | xmlWriter.WriteStartElement("Node"); 34 | xmlWriter.WriteAttributeString("Id", nodeId); 35 | xmlWriter.WriteAttributeString("Label", label); 36 | 37 | if (node.Kind == CFGNodeKind.Entry || 38 | node.Kind == CFGNodeKind.Exit) 39 | { 40 | xmlWriter.WriteAttributeString("Background", "Yellow"); 41 | } 42 | 43 | xmlWriter.WriteEndElement(); 44 | } 45 | 46 | xmlWriter.WriteEndElement(); 47 | xmlWriter.WriteStartElement("Links"); 48 | 49 | foreach (var node in cfg.Nodes) 50 | { 51 | var sourceId = Convert.ToString(node.Id); 52 | 53 | foreach (var successor in node.Successors) 54 | { 55 | var targetId = Convert.ToString(successor.Id); 56 | 57 | xmlWriter.WriteStartElement("Link"); 58 | xmlWriter.WriteAttributeString("Source", sourceId); 59 | xmlWriter.WriteAttributeString("Target", targetId); 60 | xmlWriter.WriteEndElement(); 61 | } 62 | } 63 | 64 | xmlWriter.WriteEndElement(); 65 | xmlWriter.WriteStartElement("Styles"); 66 | xmlWriter.WriteStartElement("Style"); 67 | xmlWriter.WriteAttributeString("TargetType", "Node"); 68 | 69 | xmlWriter.WriteStartElement("Setter"); 70 | xmlWriter.WriteAttributeString("Property", "FontFamily"); 71 | xmlWriter.WriteAttributeString("Value", "Consolas"); 72 | xmlWriter.WriteEndElement(); 73 | 74 | xmlWriter.WriteStartElement("Setter"); 75 | xmlWriter.WriteAttributeString("Property", "NodeRadius"); 76 | xmlWriter.WriteAttributeString("Value", "5"); 77 | xmlWriter.WriteEndElement(); 78 | 79 | xmlWriter.WriteStartElement("Setter"); 80 | xmlWriter.WriteAttributeString("Property", "MinWidth"); 81 | xmlWriter.WriteAttributeString("Value", "0"); 82 | xmlWriter.WriteEndElement(); 83 | 84 | xmlWriter.WriteEndElement(); 85 | xmlWriter.WriteEndElement(); 86 | xmlWriter.WriteEndElement(); 87 | xmlWriter.Flush(); 88 | return stringWriter.ToString(); 89 | } 90 | } 91 | 92 | private static string Serialize(CFGNode node) 93 | { 94 | string result; 95 | 96 | switch (node.Kind) 97 | { 98 | case CFGNodeKind.Entry: result = "entry"; break; 99 | case CFGNodeKind.Exit: result = "exit"; break; 100 | default: result = string.Join(Environment.NewLine, node.Instructions); break; 101 | } 102 | 103 | return result; 104 | } 105 | 106 | #endregion 107 | 108 | #region Points-To Graph 109 | 110 | public static string Serialize(PointsToGraph ptg) 111 | { 112 | using (var stringWriter = new StringWriter()) 113 | using (var xmlWriter = new XmlTextWriter(stringWriter)) 114 | { 115 | xmlWriter.Formatting = Formatting.Indented; 116 | xmlWriter.WriteStartElement("DirectedGraph"); 117 | xmlWriter.WriteAttributeString("xmlns", "http://schemas.microsoft.com/vs/2009/dgml"); 118 | xmlWriter.WriteStartElement("Nodes"); 119 | 120 | foreach (var variable in ptg.Variables) 121 | { 122 | var label = variable.Name; 123 | 124 | xmlWriter.WriteStartElement("Node"); 125 | xmlWriter.WriteAttributeString("Id", label); 126 | xmlWriter.WriteAttributeString("Label", label); 127 | xmlWriter.WriteAttributeString("Shape", "None"); 128 | xmlWriter.WriteEndElement(); 129 | } 130 | 131 | foreach (var node in ptg.Nodes) 132 | { 133 | var nodeId = Convert.ToString(node.Id); 134 | var label = DGMLSerializer.Serialize(node); 135 | 136 | xmlWriter.WriteStartElement("Node"); 137 | xmlWriter.WriteAttributeString("Id", nodeId); 138 | xmlWriter.WriteAttributeString("Label", label); 139 | 140 | if (node.Kind == PTGNodeKind.Null) 141 | { 142 | xmlWriter.WriteAttributeString("Background", "Yellow"); 143 | } 144 | else if (node.Kind == PTGNodeKind.Unknown) 145 | { 146 | xmlWriter.WriteAttributeString("Background", "#FFB445"); 147 | xmlWriter.WriteAttributeString("StrokeDashArray", "6,6"); 148 | } 149 | 150 | xmlWriter.WriteEndElement(); 151 | } 152 | 153 | xmlWriter.WriteEndElement(); 154 | xmlWriter.WriteStartElement("Links"); 155 | 156 | foreach (var node in ptg.Nodes) 157 | { 158 | var targetId = Convert.ToString(node.Id); 159 | 160 | foreach (var variable in node.Variables) 161 | { 162 | var sourceId = variable.Name; 163 | 164 | xmlWriter.WriteStartElement("Link"); 165 | xmlWriter.WriteAttributeString("Source", sourceId); 166 | xmlWriter.WriteAttributeString("Target", targetId); 167 | xmlWriter.WriteEndElement(); 168 | } 169 | 170 | var fieldsBySource = from e in node.Sources 171 | from s in e.Value 172 | group e.Key by s into g 173 | select g; 174 | 175 | foreach (var g in fieldsBySource) 176 | { 177 | var sourceId = Convert.ToString(g.Key.Id); 178 | var label = DGMLSerializer.GetLabel(g); 179 | 180 | xmlWriter.WriteStartElement("Link"); 181 | xmlWriter.WriteAttributeString("Source", sourceId); 182 | xmlWriter.WriteAttributeString("Target", targetId); 183 | xmlWriter.WriteAttributeString("Label", label); 184 | xmlWriter.WriteEndElement(); 185 | } 186 | } 187 | 188 | xmlWriter.WriteEndElement(); 189 | xmlWriter.WriteStartElement("Styles"); 190 | xmlWriter.WriteStartElement("Style"); 191 | xmlWriter.WriteAttributeString("TargetType", "Node"); 192 | 193 | xmlWriter.WriteStartElement("Setter"); 194 | xmlWriter.WriteAttributeString("Property", "FontFamily"); 195 | xmlWriter.WriteAttributeString("Value", "Consolas"); 196 | xmlWriter.WriteEndElement(); 197 | 198 | xmlWriter.WriteStartElement("Setter"); 199 | xmlWriter.WriteAttributeString("Property", "NodeRadius"); 200 | xmlWriter.WriteAttributeString("Value", "5"); 201 | xmlWriter.WriteEndElement(); 202 | 203 | xmlWriter.WriteStartElement("Setter"); 204 | xmlWriter.WriteAttributeString("Property", "MinWidth"); 205 | xmlWriter.WriteAttributeString("Value", "0"); 206 | xmlWriter.WriteEndElement(); 207 | 208 | xmlWriter.WriteEndElement(); 209 | xmlWriter.WriteEndElement(); 210 | xmlWriter.WriteEndElement(); 211 | xmlWriter.Flush(); 212 | return stringWriter.ToString(); 213 | } 214 | } 215 | 216 | private static string Serialize(PTGNode node) 217 | { 218 | string result; 219 | 220 | switch (node.Kind) 221 | { 222 | case PTGNodeKind.Null: result = "null"; break; 223 | default: result = TypeHelper.GetTypeName(node.Type); break; 224 | } 225 | 226 | return result; 227 | } 228 | 229 | #endregion 230 | 231 | #region Type Graph 232 | 233 | public static string Serialize(INamedTypeReference type) 234 | { 235 | var types = new INamedTypeReference[] { type }; 236 | return DGMLSerializer.Serialize(type); 237 | } 238 | 239 | public static string Serialize(IModule module) 240 | { 241 | var types = module.GetAllTypes(); 242 | return DGMLSerializer.Serialize(types); 243 | } 244 | 245 | private static string Serialize(IEnumerable types) 246 | { 247 | using (var stringWriter = new StringWriter()) 248 | using (var xmlWriter = new XmlTextWriter(stringWriter)) 249 | { 250 | var allTypes = new Dictionary(); 251 | var visitedTypes = new HashSet(); 252 | var newTypes = new HashSet(); 253 | 254 | xmlWriter.Formatting = Formatting.Indented; 255 | xmlWriter.WriteStartElement("DirectedGraph"); 256 | xmlWriter.WriteAttributeString("xmlns", "http://schemas.microsoft.com/vs/2009/dgml"); 257 | xmlWriter.WriteStartElement("Links"); 258 | 259 | foreach (var type in types) 260 | { 261 | allTypes.Add(type, allTypes.Count); 262 | 263 | if (type is INamedTypeDefinition) 264 | { 265 | var namedType = type as INamedTypeDefinition; 266 | newTypes.Add(namedType); 267 | } 268 | } 269 | 270 | while (newTypes.Count > 0) 271 | { 272 | var type = newTypes.First(); 273 | newTypes.Remove(type); 274 | visitedTypes.Add(type); 275 | 276 | var typeId = allTypes[type]; 277 | var sourceId = Convert.ToString(typeId); 278 | 279 | var fieldsByType = from f in type.Fields 280 | group f by f.Type into g 281 | select g; 282 | 283 | foreach (var g in fieldsByType) 284 | { 285 | if (g.Key is INamedTypeReference) 286 | { 287 | var fieldType = g.Key as INamedTypeReference; 288 | 289 | if (!allTypes.ContainsKey(fieldType)) 290 | { 291 | allTypes.Add(fieldType, allTypes.Count); 292 | } 293 | 294 | if (fieldType is INamedTypeDefinition) 295 | { 296 | var namedFieldType = fieldType as INamedTypeDefinition; 297 | 298 | if (!visitedTypes.Contains(namedFieldType)) 299 | { 300 | newTypes.Add(namedFieldType); 301 | } 302 | } 303 | 304 | typeId = allTypes[fieldType]; 305 | var targetId = Convert.ToString(typeId); 306 | var label = DGMLSerializer.GetLabel(g); 307 | 308 | xmlWriter.WriteStartElement("Link"); 309 | xmlWriter.WriteAttributeString("Source", sourceId); 310 | xmlWriter.WriteAttributeString("Target", targetId); 311 | xmlWriter.WriteAttributeString("Label", label); 312 | xmlWriter.WriteEndElement(); 313 | } 314 | } 315 | } 316 | 317 | xmlWriter.WriteEndElement(); 318 | xmlWriter.WriteStartElement("Nodes"); 319 | 320 | foreach (var entry in allTypes) 321 | { 322 | var typeId = Convert.ToString(entry.Value); 323 | var label = TypeHelper.GetTypeName(entry.Key); 324 | 325 | xmlWriter.WriteStartElement("Node"); 326 | xmlWriter.WriteAttributeString("Id", typeId); 327 | xmlWriter.WriteAttributeString("Label", label); 328 | xmlWriter.WriteEndElement(); 329 | } 330 | 331 | xmlWriter.WriteEndElement(); 332 | xmlWriter.WriteStartElement("Styles"); 333 | xmlWriter.WriteStartElement("Style"); 334 | xmlWriter.WriteAttributeString("TargetType", "Node"); 335 | 336 | xmlWriter.WriteStartElement("Setter"); 337 | xmlWriter.WriteAttributeString("Property", "FontFamily"); 338 | xmlWriter.WriteAttributeString("Value", "Consolas"); 339 | xmlWriter.WriteEndElement(); 340 | 341 | xmlWriter.WriteStartElement("Setter"); 342 | xmlWriter.WriteAttributeString("Property", "NodeRadius"); 343 | xmlWriter.WriteAttributeString("Value", "5"); 344 | xmlWriter.WriteEndElement(); 345 | 346 | xmlWriter.WriteStartElement("Setter"); 347 | xmlWriter.WriteAttributeString("Property", "MinWidth"); 348 | xmlWriter.WriteAttributeString("Value", "0"); 349 | xmlWriter.WriteEndElement(); 350 | 351 | xmlWriter.WriteEndElement(); 352 | xmlWriter.WriteEndElement(); 353 | xmlWriter.WriteEndElement(); 354 | xmlWriter.Flush(); 355 | return stringWriter.ToString(); 356 | } 357 | } 358 | 359 | #endregion 360 | 361 | #region Private Methods 362 | 363 | private static string GetLabel(IEnumerable fields) 364 | { 365 | var result = new StringBuilder(); 366 | 367 | foreach (var field in fields) 368 | { 369 | var fieldName = MemberHelper.GetMemberSignature(field, NameFormattingOptions.OmitContainingType | NameFormattingOptions.PreserveSpecialNames); 370 | 371 | result.Append(fieldName); 372 | result.AppendLine(); 373 | } 374 | 375 | result.Remove(result.Length - 2, 2); 376 | return result.ToString(); 377 | } 378 | 379 | #endregion 380 | } 381 | } 382 | -------------------------------------------------------------------------------- /Backend/Serialization/DOTSerializer.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Edgardo Zoppi. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. 2 | 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using Backend.Analysis; 8 | 9 | namespace Backend.Serialization 10 | { 11 | public static class DOTSerializer 12 | { 13 | public static string Serialize(ControlFlowGraph cfg) 14 | { 15 | var sb = new StringBuilder(); 16 | sb.AppendLine("digraph ControlFlow\n{"); 17 | sb.AppendLine("\tnode[shape=\"rect\"];"); 18 | 19 | foreach (var node in cfg.Nodes) 20 | { 21 | var label = DOTSerializer.Serialize(node); 22 | sb.AppendFormat("\t{0}[label=\"{1}\"];\n", node.Id, label); 23 | 24 | foreach (var successor in node.Successors) 25 | { 26 | sb.AppendFormat("\t{0} -> {1};\n", node.Id, successor.Id); 27 | } 28 | } 29 | 30 | sb.AppendLine("}"); 31 | return sb.ToString(); 32 | } 33 | 34 | private static string Serialize(CFGNode node) 35 | { 36 | string result; 37 | 38 | switch (node.Kind) 39 | { 40 | case CFGNodeKind.Entry: result = "entry"; break; 41 | case CFGNodeKind.Exit: result = "exit"; break; 42 | default: result = string.Join("\\l", node.Instructions) + "\\l"; break; 43 | } 44 | 45 | return result; 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Backend/ThreeAddressCode/ExceptionHandlers.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Edgardo Zoppi. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. 2 | 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using Microsoft.Cci; 8 | 9 | namespace Backend.ThreeAddressCode 10 | { 11 | public enum ExceptionHandlerBlockKind 12 | { 13 | Try, 14 | Catch, 15 | Fault, 16 | Finally 17 | } 18 | 19 | public interface IExceptionHandlerBlock 20 | { 21 | ExceptionHandlerBlockKind Kind { get; } 22 | string Start { get; } 23 | string End { get; } 24 | } 25 | 26 | public interface IExceptionHandler : IExceptionHandlerBlock 27 | { 28 | } 29 | 30 | public class ProtectedBlock : IExceptionHandlerBlock 31 | { 32 | public ExceptionHandlerBlockKind Kind { get; private set; } 33 | public string Start { get; set; } 34 | public string End { get; set; } 35 | public IExceptionHandler Handler { get; set; } 36 | 37 | public ProtectedBlock(uint start, uint end) 38 | { 39 | this.Kind = ExceptionHandlerBlockKind.Try; 40 | this.Start = string.Format("L_{0:X4}", start); 41 | this.End = string.Format("L_{0:X4}", end); 42 | } 43 | 44 | public override string ToString() 45 | { 46 | return string.Format("try {0} to {1} {2}", this.Start, this.End, this.Handler); 47 | } 48 | } 49 | 50 | public class CatchExceptionHandler : IExceptionHandler 51 | { 52 | public ExceptionHandlerBlockKind Kind { get; private set; } 53 | public string Start { get; set; } 54 | public string End { get; set; } 55 | public ITypeReference ExceptionType { get; set; } 56 | 57 | public CatchExceptionHandler(uint start, uint end, ITypeReference exceptionType) 58 | { 59 | this.Kind = ExceptionHandlerBlockKind.Catch; 60 | this.Start = string.Format("L_{0:X4}", start); 61 | this.End = string.Format("L_{0:X4}", end); 62 | this.ExceptionType = exceptionType; 63 | } 64 | 65 | public override string ToString() 66 | { 67 | var type = TypeHelper.GetTypeName(this.ExceptionType); 68 | return string.Format("catch {0} handler {1} to {2}", type, this.Start, this.End); 69 | } 70 | } 71 | 72 | public class FaultExceptionHandler : IExceptionHandler 73 | { 74 | public ExceptionHandlerBlockKind Kind { get; private set; } 75 | public string Start { get; set; } 76 | public string End { get; set; } 77 | 78 | public FaultExceptionHandler(uint start, uint end) 79 | { 80 | this.Kind = ExceptionHandlerBlockKind.Fault; 81 | this.Start = string.Format("L_{0:X4}", start); 82 | this.End = string.Format("L_{0:X4}", end); 83 | } 84 | 85 | public override string ToString() 86 | { 87 | return string.Format("fault handler {0} to {1}", this.Start, this.End); 88 | } 89 | } 90 | 91 | public class FinallyExceptionHandler : IExceptionHandler 92 | { 93 | public ExceptionHandlerBlockKind Kind { get; private set; } 94 | public string Start { get; set; } 95 | public string End { get; set; } 96 | 97 | public FinallyExceptionHandler(uint start, uint end) 98 | { 99 | this.Kind = ExceptionHandlerBlockKind.Finally; 100 | this.Start = string.Format("L_{0:X4}", start); 101 | this.End = string.Format("L_{0:X4}", end); 102 | } 103 | 104 | public override string ToString() 105 | { 106 | return string.Format("finally handler {0} to {1}", this.Start, this.End); 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /Backend/ThreeAddressCode/TypeDefinitions.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Edgardo Zoppi. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. 2 | 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using Backend.ThreeAddressCode.Values; 8 | 9 | namespace Backend.ThreeAddressCode.Types 10 | { 11 | public interface ITypeDefinition 12 | { 13 | string Name { get; set; } 14 | } 15 | 16 | public interface IValueTypeDefinition : ITypeDefinition 17 | { 18 | } 19 | 20 | public interface IReferenceTypeDefinition : ITypeDefinition 21 | { 22 | } 23 | 24 | public class StructDefinition : IValueTypeDefinition 25 | { 26 | public string Name { get; set; } 27 | public IList GenericParameters { get; private set; } 28 | public IDictionary Fields { get; private set; } 29 | public IDictionary Methods { get; private set; } 30 | 31 | public StructDefinition(string name) 32 | { 33 | this.Name = name; 34 | this.GenericParameters = new List(); 35 | this.Fields = new Dictionary(); 36 | this.Methods = new Dictionary(); 37 | } 38 | 39 | public override string ToString() 40 | { 41 | var result = new StringBuilder(); 42 | result.AppendFormat("struct {0}", this.Name); 43 | 44 | if (this.GenericParameters.Count > 0) 45 | { 46 | var gparameters = string.Join(", ", this.GenericParameters); 47 | result.AppendFormat("<{0}>", gparameters); 48 | } 49 | 50 | result.AppendLine(); 51 | result.AppendLine("{"); 52 | 53 | foreach (var field in this.Fields.Values) 54 | { 55 | result.AppendFormat(" {0};\n", field); 56 | } 57 | 58 | foreach (var method in this.Methods.Values) 59 | { 60 | result.AppendFormat(" {0};\n", method); 61 | } 62 | 63 | result.AppendLine("}"); 64 | return result.ToString(); 65 | } 66 | } 67 | 68 | public class FieldDefinition 69 | { 70 | public IType Type { get; set; } 71 | public string Name { get; set; } 72 | public bool IsStatic { get; set; } 73 | 74 | public FieldDefinition(string name, IType type) 75 | { 76 | this.Name = name; 77 | this.Type = type; 78 | } 79 | 80 | public override string ToString() 81 | { 82 | var modifier = this.IsStatic ? "static " : string.Empty; 83 | return string.Format("{0}{1} {2}", modifier, this.Type, this.Name); 84 | } 85 | } 86 | 87 | public class MethodDefinition 88 | { 89 | public IType ReturnType { get; set; } 90 | public string Name { get; set; } 91 | public IList GenericParameters { get; private set; } 92 | public IList Parameters { get; private set; } 93 | public bool IsStatic { get; set; } 94 | public bool IsConstructor { get; set; } 95 | 96 | public MethodDefinition(string name, IType returnType) 97 | { 98 | this.Name = name; 99 | this.ReturnType = returnType; 100 | this.GenericParameters = new List(); 101 | this.Parameters = new List(); 102 | } 103 | 104 | public override string ToString() 105 | { 106 | var result = new StringBuilder(); 107 | 108 | if (this.IsStatic) 109 | { 110 | result.Append("static "); 111 | } 112 | 113 | result.AppendFormat("{0} {1}", this.ReturnType, this.Name); 114 | 115 | if (this.GenericParameters.Count > 0) 116 | { 117 | var gparameters = string.Join(", ", this.GenericParameters); 118 | result.AppendFormat("<{0}>", gparameters); 119 | } 120 | 121 | var parameters = string.Join(", ", this.Parameters); 122 | result.AppendFormat("({0})", parameters); 123 | return result.ToString(); 124 | } 125 | } 126 | 127 | public class EnumDefinition : IValueTypeDefinition 128 | { 129 | public string Name { get; set; } 130 | public BasicType UnderlayingType { get; set; } 131 | public IDictionary Constants { get; private set; } 132 | 133 | public EnumDefinition(string name) 134 | { 135 | this.Name = name; 136 | this.Constants = new Dictionary(); 137 | } 138 | 139 | public override string ToString() 140 | { 141 | var result = new StringBuilder(); 142 | result.AppendFormat("enum {0} : {1}\n", this.Name, this.UnderlayingType); 143 | result.AppendLine("{"); 144 | 145 | foreach (var constant in this.Constants) 146 | { 147 | result.AppendFormat(" {0} = {1};\n", constant.Key, constant.Value); 148 | } 149 | 150 | result.AppendLine("}"); 151 | return result.ToString(); 152 | } 153 | } 154 | 155 | public class InterfaceDefinition : IReferenceTypeDefinition 156 | { 157 | public string Name { get; set; } 158 | public IList Interfaces { get; private set; } 159 | public IList GenericParameters { get; private set; } 160 | public IDictionary Methods { get; private set; } 161 | 162 | public InterfaceDefinition(string name) 163 | { 164 | this.Name = name; 165 | this.Interfaces = new List(); 166 | this.GenericParameters = new List(); 167 | this.Methods = new Dictionary(); 168 | } 169 | 170 | public override string ToString() 171 | { 172 | var result = new StringBuilder(); 173 | result.AppendFormat("interface {0}", this.Name); 174 | 175 | if (this.GenericParameters.Count > 0) 176 | { 177 | var gparameters = string.Join(", ", this.GenericParameters); 178 | result.AppendFormat("<{0}>", gparameters); 179 | } 180 | 181 | if (this.Interfaces.Count > 0) 182 | { 183 | var interfaces = string.Join(", ", this.Interfaces); 184 | result.AppendFormat(" : {0}", interfaces); 185 | } 186 | 187 | result.AppendLine(); 188 | result.AppendLine("{"); 189 | 190 | foreach (var method in this.Methods.Values) 191 | { 192 | result.AppendFormat(" {0};\n", method); 193 | } 194 | 195 | result.AppendLine("}"); 196 | return result.ToString(); 197 | } 198 | } 199 | 200 | public class ClassDefinition : IReferenceTypeDefinition 201 | { 202 | public string Name { get; set; } 203 | public BasicType Base { get; set; } 204 | public IList Interfaces { get; private set; } 205 | public IList GenericParameters { get; private set; } 206 | public IDictionary Fields { get; private set; } 207 | public IDictionary Methods { get; private set; } 208 | 209 | public ClassDefinition(string name) 210 | { 211 | this.Name = name; 212 | this.Interfaces = new List(); 213 | this.GenericParameters = new List(); 214 | this.Fields = new Dictionary(); 215 | this.Methods = new Dictionary(); 216 | } 217 | 218 | public override string ToString() 219 | { 220 | var result = new StringBuilder(); 221 | result.AppendFormat("class {0}", this.Name); 222 | 223 | if (this.GenericParameters.Count > 0) 224 | { 225 | var gparameters = string.Join(", ", this.GenericParameters); 226 | result.AppendFormat("<{0}>", gparameters); 227 | } 228 | 229 | result.AppendFormat(" : {0}", this.Base); 230 | 231 | if (this.Interfaces.Count > 0) 232 | { 233 | var interfaces = string.Join(", ", this.Interfaces); 234 | result.AppendFormat(", {0}", interfaces); 235 | } 236 | 237 | result.AppendLine(); 238 | result.AppendLine("{"); 239 | 240 | foreach (var field in this.Fields.Values) 241 | { 242 | result.AppendFormat(" {0};\n", field); 243 | } 244 | 245 | foreach (var field in this.Fields.Values) 246 | { 247 | result.AppendFormat(" {0};\n", field); 248 | } 249 | 250 | foreach (var method in this.Methods.Values) 251 | { 252 | result.AppendFormat(" {0};\n", method); 253 | } 254 | 255 | result.AppendLine("}"); 256 | return result.ToString(); 257 | } 258 | } 259 | } 260 | -------------------------------------------------------------------------------- /Backend/ThreeAddressCode/Types.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Edgardo Zoppi. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. 2 | 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | 8 | namespace Backend.ThreeAddressCode.Types 9 | { 10 | public interface IType 11 | { 12 | } 13 | 14 | public interface IValueType : IType 15 | { 16 | 17 | } 18 | 19 | public interface IReferenceType : IType 20 | { 21 | 22 | } 23 | 24 | public enum PrimitiveTypeKind 25 | { 26 | Bool, 27 | Byte, 28 | SByte, 29 | Char, 30 | Decimal, 31 | Double, 32 | Float, 33 | Short, 34 | Int, 35 | Long, 36 | UShort, 37 | UInt, 38 | ULong 39 | } 40 | 41 | public class PrimitiveType : IValueType 42 | { 43 | public PrimitiveTypeKind Kind { get; set; } 44 | 45 | public PrimitiveType(PrimitiveTypeKind kind) 46 | { 47 | this.Kind = kind; 48 | } 49 | 50 | public string Name 51 | { 52 | get 53 | { 54 | var result = string.Empty; 55 | 56 | switch (this.Kind) 57 | { 58 | case PrimitiveTypeKind.Bool: result = "bool"; break; 59 | case PrimitiveTypeKind.Byte: result = "byte"; break; 60 | case PrimitiveTypeKind.SByte: result = "sbyte"; break; 61 | case PrimitiveTypeKind.Char: result = "char"; break; 62 | case PrimitiveTypeKind.Decimal: result = "decimal"; break; 63 | case PrimitiveTypeKind.Double: result = "double"; break; 64 | case PrimitiveTypeKind.Float: result = "float"; break; 65 | case PrimitiveTypeKind.Short: result = "short"; break; 66 | case PrimitiveTypeKind.Int: result = "int"; break; 67 | case PrimitiveTypeKind.Long: result = "long"; break; 68 | case PrimitiveTypeKind.UShort: result = "ushort"; break; 69 | case PrimitiveTypeKind.UInt: result = "uint"; break; 70 | case PrimitiveTypeKind.ULong: result = "ulong"; break; 71 | } 72 | 73 | return result; 74 | } 75 | } 76 | 77 | public override string ToString() 78 | { 79 | return this.Name; 80 | } 81 | } 82 | 83 | public static class PrimitiveTypes 84 | { 85 | public static UnknownType UnknownType 86 | { 87 | get { return UnknownType.Value; } 88 | } 89 | 90 | public static UnknownType Int32 91 | { 92 | get { return null; } 93 | } 94 | 95 | public static UnknownType IntPtr 96 | { 97 | get { return null; } 98 | } 99 | } 100 | 101 | public class UnknownType : IType 102 | { 103 | private static UnknownType value; 104 | 105 | private UnknownType() { } 106 | 107 | public static UnknownType Value 108 | { 109 | get 110 | { 111 | if (value == null) value = new UnknownType(); 112 | return value; 113 | } 114 | } 115 | 116 | public override string ToString() 117 | { 118 | return "UNK"; 119 | } 120 | } 121 | 122 | public class BasicType : IType 123 | { 124 | public string Name { get; set; } 125 | public IList GenericArguments { get; private set; } 126 | 127 | public BasicType(string name) 128 | { 129 | this.Name = name; 130 | this.GenericArguments = new List(); 131 | } 132 | 133 | public override string ToString() 134 | { 135 | var arguments = string.Empty; 136 | 137 | if (this.GenericArguments.Count > 0) 138 | { 139 | arguments = string.Join(", ", this.GenericArguments); 140 | arguments = string.Format("<{0}>", arguments); 141 | } 142 | 143 | return string.Format("{0}{1}", this.Name, arguments); 144 | } 145 | } 146 | 147 | public class TypeVariable : IType 148 | { 149 | public string Name { get; set; } 150 | 151 | public TypeVariable(string name) 152 | { 153 | this.Name = name; 154 | } 155 | 156 | public override string ToString() 157 | { 158 | return this.Name; 159 | } 160 | } 161 | 162 | public class PointerType : IReferenceType 163 | { 164 | public IType TargetType { get; set; } 165 | 166 | public PointerType(IType targetType) 167 | { 168 | this.TargetType = targetType; 169 | } 170 | 171 | public override string ToString() 172 | { 173 | return string.Format("{0}*", this.TargetType); 174 | } 175 | } 176 | 177 | public class ArrayType : IReferenceType 178 | { 179 | public IType ElementsType { get; set; } 180 | 181 | public ArrayType(IType elementsType) 182 | { 183 | this.ElementsType = elementsType; 184 | } 185 | 186 | public override string ToString() 187 | { 188 | return string.Format("{0}[]", this.ElementsType); 189 | } 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /Backend/Types.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Edgardo Zoppi. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. 2 | 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using Microsoft.Cci; 8 | using Microsoft.Cci.Immutable; 9 | 10 | namespace Backend 11 | { 12 | public class Types 13 | { 14 | private IMetadataHost host; 15 | 16 | public static Types Instance { get; private set; } 17 | 18 | public static void Initialize(IMetadataHost host) 19 | { 20 | Types.Instance = new Types(host); 21 | } 22 | 23 | private Types(IMetadataHost host) 24 | { 25 | this.host = host; 26 | 27 | var unit = host.FindUnit(host.CoreAssemblySymbolicIdentity); 28 | this.PureAttributeType = UnitHelper.FindType(host.NameTable, unit, "System.Diagnostics.Contracts.PureAttribute"); 29 | } 30 | 31 | public ITypeReference PureAttributeType { get; private set; } 32 | 33 | public IPlatformType PlatformType 34 | { 35 | get { return host.PlatformType; } 36 | } 37 | 38 | public ITypeReference ArrayLengthType 39 | { 40 | get { return host.PlatformType.SystemUIntPtr; } 41 | } 42 | 43 | public ITypeReference SizeofType 44 | { 45 | get { return host.PlatformType.SystemUInt32; } 46 | } 47 | 48 | public ITypeReference NativePointerType 49 | { 50 | get { return host.PlatformType.SystemIntPtr; } 51 | } 52 | 53 | public ITypeReference ArrayType(ITypeReference elementType, uint rank) 54 | { 55 | var type = Matrix.GetMatrix(elementType, rank, host.InternFactory); 56 | return type; 57 | } 58 | 59 | public ITypeReference ArrayElementType(ITypeReference arrayType) 60 | { 61 | var type = arrayType as IArrayTypeReference; 62 | return type.ElementType; 63 | } 64 | 65 | public ITypeReference PointerTargetType(ITypeReference pointerType) 66 | { 67 | ITypeReference result = null; 68 | 69 | if (pointerType is IPointerTypeReference) 70 | { 71 | var type = pointerType as IPointerTypeReference; 72 | result = type.TargetType; 73 | } 74 | else if (pointerType is IManagedPointerTypeReference) 75 | { 76 | var type = pointerType as IManagedPointerTypeReference; 77 | result = type.TargetType; 78 | } 79 | 80 | return result; 81 | } 82 | 83 | public ITypeReference PointerType(ITypeReference targetType) 84 | { 85 | var type = ManagedPointerType.GetManagedPointerType(targetType, host.InternFactory); 86 | return type; 87 | } 88 | 89 | public ITypeReference FunctionPointerType(ISignature signature) 90 | { 91 | var type = new FunctionPointerType(signature, host.InternFactory); 92 | return type; 93 | } 94 | 95 | public ITypeReference TokenType(IReference token) 96 | { 97 | var type = host.PlatformType.SystemVoid; 98 | 99 | if (token is IMethodReference) 100 | { 101 | type = host.PlatformType.SystemRuntimeMethodHandle; 102 | } 103 | else if (token is ITypeReference) 104 | { 105 | type = host.PlatformType.SystemRuntimeTypeHandle; 106 | } 107 | else if (token is IFieldReference) 108 | { 109 | type = host.PlatformType.SystemRuntimeFieldHandle; 110 | } 111 | 112 | return type; 113 | } 114 | 115 | public ITypeReference BinaryLogicalOperationType(ITypeReference left, ITypeReference right) 116 | { 117 | ITypeReference type = null; 118 | 119 | if (left.TypeCode == PrimitiveTypeCode.Boolean && right.TypeCode == PrimitiveTypeCode.Boolean) 120 | { 121 | type = host.PlatformType.SystemBoolean; 122 | } 123 | else 124 | { 125 | type = this.BinarySignedNumericOperationType(left, right); 126 | } 127 | 128 | return type; 129 | } 130 | 131 | public ITypeReference BinaryNumericOperationType(ITypeReference left, ITypeReference right, bool unsigned) 132 | { 133 | var type = this.BinarySignedNumericOperationType(left, right); 134 | 135 | if (unsigned) 136 | { 137 | type = TypeHelper.UnsignedEquivalent(type); 138 | } 139 | 140 | return type; 141 | } 142 | 143 | public ITypeReference BinaryUnsignedNumericOperationType(ITypeReference left, ITypeReference right) 144 | { 145 | var type = this.BinaryNumericOperationType(left, right, true); 146 | return type; 147 | } 148 | 149 | public ITypeReference BinarySignedNumericOperationType(ITypeReference left, ITypeReference right) 150 | { 151 | switch (left.TypeCode) 152 | { 153 | case PrimitiveTypeCode.Boolean: 154 | case PrimitiveTypeCode.Char: 155 | case PrimitiveTypeCode.UInt16: 156 | case PrimitiveTypeCode.UInt32: 157 | case PrimitiveTypeCode.UInt8: 158 | switch (right.TypeCode) 159 | { 160 | case PrimitiveTypeCode.Boolean: 161 | case PrimitiveTypeCode.Char: 162 | case PrimitiveTypeCode.UInt16: 163 | case PrimitiveTypeCode.UInt32: 164 | case PrimitiveTypeCode.UInt8: 165 | return host.PlatformType.SystemUInt32; 166 | 167 | case PrimitiveTypeCode.Int8: 168 | case PrimitiveTypeCode.Int16: 169 | case PrimitiveTypeCode.Int32: 170 | // Code generators will tend to make both operands be of the same type. 171 | // Assume this happened because the right operand is a polymorphic constant. 172 | return host.PlatformType.SystemUInt32; 173 | 174 | //The cases below are not expected to happen in practice 175 | case PrimitiveTypeCode.UInt64: 176 | case PrimitiveTypeCode.Int64: 177 | return host.PlatformType.SystemUInt64; 178 | 179 | case PrimitiveTypeCode.UIntPtr: 180 | case PrimitiveTypeCode.IntPtr: 181 | return host.PlatformType.SystemUIntPtr; 182 | 183 | case PrimitiveTypeCode.Float32: 184 | return host.PlatformType.SystemFloat32; 185 | 186 | case PrimitiveTypeCode.Float64: 187 | return host.PlatformType.SystemFloat64; 188 | 189 | default: 190 | // Code generators will tend to make both operands be of the same type. 191 | // Assume this happened because the right operand is an enum. 192 | return right; 193 | } 194 | 195 | case PrimitiveTypeCode.Int8: 196 | case PrimitiveTypeCode.Int16: 197 | case PrimitiveTypeCode.Int32: 198 | switch (right.TypeCode) 199 | { 200 | case PrimitiveTypeCode.Boolean: 201 | case PrimitiveTypeCode.Char: 202 | case PrimitiveTypeCode.UInt16: 203 | case PrimitiveTypeCode.UInt32: 204 | case PrimitiveTypeCode.UInt8: 205 | // Code generators will tend to make both operands be of the same type. 206 | // Assume this happened because the left operand is a polymorphic constant. 207 | return host.PlatformType.SystemUInt32; 208 | 209 | case PrimitiveTypeCode.Int8: 210 | case PrimitiveTypeCode.Int16: 211 | case PrimitiveTypeCode.Int32: 212 | return host.PlatformType.SystemInt32; 213 | 214 | // The cases below are not expected to happen in practice 215 | case PrimitiveTypeCode.UInt64: 216 | return host.PlatformType.SystemUInt64; 217 | 218 | case PrimitiveTypeCode.Int64: 219 | return host.PlatformType.SystemInt64; 220 | 221 | case PrimitiveTypeCode.UIntPtr: 222 | return host.PlatformType.SystemUIntPtr; 223 | 224 | case PrimitiveTypeCode.IntPtr: 225 | return host.PlatformType.SystemIntPtr; 226 | 227 | case PrimitiveTypeCode.Float32: 228 | return host.PlatformType.SystemFloat32; 229 | 230 | case PrimitiveTypeCode.Float64: 231 | return host.PlatformType.SystemFloat64; 232 | 233 | default: 234 | // Code generators will tend to make both operands be of the same type. 235 | // Assume this happened because the right operand is an enum. 236 | return right; 237 | } 238 | 239 | case PrimitiveTypeCode.UInt64: 240 | switch (right.TypeCode) 241 | { 242 | case PrimitiveTypeCode.Boolean: 243 | case PrimitiveTypeCode.Char: 244 | case PrimitiveTypeCode.UInt16: 245 | case PrimitiveTypeCode.UInt32: 246 | case PrimitiveTypeCode.UInt8: 247 | case PrimitiveTypeCode.UInt64: 248 | return host.PlatformType.SystemUInt64; 249 | 250 | case PrimitiveTypeCode.Int8: 251 | case PrimitiveTypeCode.Int16: 252 | case PrimitiveTypeCode.Int32: 253 | case PrimitiveTypeCode.Int64: 254 | // Code generators will tend to make both operands be of the same type. 255 | // Assume this happened because the right operand is a polymorphic constant. 256 | return host.PlatformType.SystemUInt64; 257 | 258 | case PrimitiveTypeCode.UIntPtr: 259 | return host.PlatformType.SystemUIntPtr; 260 | 261 | case PrimitiveTypeCode.IntPtr: 262 | return host.PlatformType.SystemIntPtr; 263 | 264 | case PrimitiveTypeCode.Float32: 265 | return host.PlatformType.SystemFloat32; 266 | 267 | case PrimitiveTypeCode.Float64: 268 | return host.PlatformType.SystemFloat64; 269 | 270 | default: 271 | // Code generators will tend to make both operands be of the same type. 272 | // Assume this happened because the right operand is an enum. 273 | return right; 274 | } 275 | 276 | case PrimitiveTypeCode.Int64: 277 | switch (right.TypeCode) 278 | { 279 | case PrimitiveTypeCode.Boolean: 280 | case PrimitiveTypeCode.Char: 281 | case PrimitiveTypeCode.UInt16: 282 | case PrimitiveTypeCode.UInt32: 283 | case PrimitiveTypeCode.UInt8: 284 | case PrimitiveTypeCode.UInt64: 285 | // Code generators will tend to make both operands be of the same type. 286 | // Assume this happened because the left operand is a polymorphic constant. 287 | return host.PlatformType.SystemUInt64; 288 | 289 | case PrimitiveTypeCode.Int8: 290 | case PrimitiveTypeCode.Int16: 291 | case PrimitiveTypeCode.Int32: 292 | case PrimitiveTypeCode.Int64: 293 | return host.PlatformType.SystemInt64; 294 | 295 | case PrimitiveTypeCode.UIntPtr: 296 | case PrimitiveTypeCode.IntPtr: 297 | return host.PlatformType.SystemIntPtr; 298 | 299 | case PrimitiveTypeCode.Float32: 300 | return host.PlatformType.SystemFloat32; 301 | 302 | case PrimitiveTypeCode.Float64: 303 | return host.PlatformType.SystemFloat64; 304 | 305 | default: 306 | // Code generators will tend to make both operands be of the same type. 307 | // Assume this happened because the right operand is an enum. 308 | return right; 309 | } 310 | 311 | case PrimitiveTypeCode.UIntPtr: 312 | switch (right.TypeCode) 313 | { 314 | case PrimitiveTypeCode.Boolean: 315 | case PrimitiveTypeCode.Char: 316 | case PrimitiveTypeCode.UInt16: 317 | case PrimitiveTypeCode.UInt32: 318 | case PrimitiveTypeCode.UInt8: 319 | case PrimitiveTypeCode.UInt64: 320 | case PrimitiveTypeCode.UIntPtr: 321 | return host.PlatformType.SystemUIntPtr; 322 | 323 | case PrimitiveTypeCode.Int8: 324 | case PrimitiveTypeCode.Int16: 325 | case PrimitiveTypeCode.Int32: 326 | case PrimitiveTypeCode.Int64: 327 | case PrimitiveTypeCode.IntPtr: 328 | return host.PlatformType.SystemUIntPtr; 329 | 330 | case PrimitiveTypeCode.Float32: 331 | return host.PlatformType.SystemFloat32; 332 | 333 | case PrimitiveTypeCode.Float64: 334 | return host.PlatformType.SystemFloat64; 335 | 336 | case PrimitiveTypeCode.Pointer: 337 | case PrimitiveTypeCode.Reference: 338 | return right; 339 | 340 | default: 341 | return null; 342 | } 343 | 344 | case PrimitiveTypeCode.IntPtr: 345 | switch (right.TypeCode) 346 | { 347 | case PrimitiveTypeCode.Boolean: 348 | case PrimitiveTypeCode.Char: 349 | case PrimitiveTypeCode.UInt16: 350 | case PrimitiveTypeCode.UInt32: 351 | case PrimitiveTypeCode.UInt8: 352 | case PrimitiveTypeCode.UInt64: 353 | case PrimitiveTypeCode.UIntPtr: 354 | return host.PlatformType.SystemUIntPtr; 355 | 356 | case PrimitiveTypeCode.Int8: 357 | case PrimitiveTypeCode.Int16: 358 | case PrimitiveTypeCode.Int32: 359 | case PrimitiveTypeCode.Int64: 360 | case PrimitiveTypeCode.IntPtr: 361 | return host.PlatformType.SystemIntPtr; 362 | 363 | case PrimitiveTypeCode.Float32: 364 | return host.PlatformType.SystemFloat32; 365 | 366 | case PrimitiveTypeCode.Float64: 367 | return host.PlatformType.SystemFloat64; 368 | 369 | case PrimitiveTypeCode.Pointer: 370 | case PrimitiveTypeCode.Reference: 371 | return right; 372 | 373 | default: 374 | return null; 375 | } 376 | 377 | case PrimitiveTypeCode.Float32: 378 | case PrimitiveTypeCode.Float64: 379 | return right; 380 | 381 | case PrimitiveTypeCode.Pointer: 382 | case PrimitiveTypeCode.Reference: 383 | switch (right.TypeCode) 384 | { 385 | case PrimitiveTypeCode.Pointer: 386 | case PrimitiveTypeCode.Reference: 387 | return host.PlatformType.SystemUIntPtr; 388 | 389 | case PrimitiveTypeCode.Int8: 390 | case PrimitiveTypeCode.Int16: 391 | case PrimitiveTypeCode.Int32: 392 | case PrimitiveTypeCode.Int64: 393 | case PrimitiveTypeCode.Char: 394 | case PrimitiveTypeCode.UInt8: 395 | case PrimitiveTypeCode.UInt16: 396 | case PrimitiveTypeCode.UInt32: 397 | case PrimitiveTypeCode.UInt64: 398 | case PrimitiveTypeCode.IntPtr: 399 | case PrimitiveTypeCode.UIntPtr: 400 | return left; 401 | 402 | case PrimitiveTypeCode.NotPrimitive: 403 | // Assume rh type is an enum. 404 | return left; 405 | 406 | default: 407 | return null; 408 | } 409 | 410 | default: 411 | switch (right.TypeCode) 412 | { 413 | case PrimitiveTypeCode.Int8: 414 | case PrimitiveTypeCode.Int16: 415 | case PrimitiveTypeCode.Int32: 416 | case PrimitiveTypeCode.Int64: 417 | case PrimitiveTypeCode.Boolean: 418 | case PrimitiveTypeCode.Char: 419 | case PrimitiveTypeCode.UInt8: 420 | case PrimitiveTypeCode.UInt16: 421 | case PrimitiveTypeCode.UInt32: 422 | case PrimitiveTypeCode.UInt64: 423 | // Assume that the left operand has an enum type. 424 | return left; 425 | } 426 | 427 | // Assume they are both enums 428 | return left; 429 | } 430 | } 431 | 432 | public bool IsContainer(ITypeReference type) 433 | { 434 | var result = false; 435 | 436 | if (type is IGenericTypeInstanceReference) 437 | { 438 | var specializedType = type as IGenericTypeInstanceReference; 439 | type = specializedType.GenericType; 440 | } 441 | 442 | var typedef = TypeHelper.Resolve(type, host); 443 | 444 | if (typedef != null && typedef != Dummy.TypeDefinition) 445 | { 446 | result = TypeHelper.Type1ImplementsType2(typedef, host.PlatformType.SystemCollectionsICollection); 447 | result = result || TypeHelper.Type1ImplementsType2(typedef, host.PlatformType.SystemCollectionsGenericICollection); 448 | } 449 | 450 | return result; 451 | } 452 | } 453 | } 454 | -------------------------------------------------------------------------------- /Backend/TypesExtractor.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Edgardo Zoppi. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. 2 | 3 | using Cci = Microsoft.Cci; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Text; 8 | using Backend.ThreeAddressCode; 9 | using Backend.ThreeAddressCode.Types; 10 | using Backend.ThreeAddressCode.Values; 11 | 12 | namespace Backend 13 | { 14 | public class TypesExtractor 15 | { 16 | #region class TypesTraverser 17 | 18 | private class TypesTraverser : Cci.MetadataTraverser 19 | { 20 | private Cci.IMetadataHost host; 21 | private IDictionary types; 22 | 23 | public TypesTraverser(Cci.IMetadataHost host) 24 | { 25 | this.host = host; 26 | this.TraverseIntoMethodBodies = false; 27 | this.types = new Dictionary(); 28 | } 29 | 30 | public IDictionary Types 31 | { 32 | get { return this.types; } 33 | } 34 | 35 | public override void TraverseChildren(Cci.INamedTypeDefinition typedef) 36 | { 37 | if (typedef.IsClass) 38 | { 39 | this.ExtractClass(typedef); 40 | } 41 | else if (typedef.IsInterface) 42 | { 43 | this.ExtractInterface(typedef); 44 | } 45 | else if (typedef.IsStruct) 46 | { 47 | this.ExtractStruct(typedef); 48 | } 49 | else if (typedef.IsEnum) 50 | { 51 | this.ExtractEnum(typedef); 52 | } 53 | 54 | base.TraverseChildren(typedef); 55 | } 56 | 57 | private void ExtractEnum(Cci.INamedTypeDefinition typedef) 58 | { 59 | var name = typedef.Name.Value; 60 | var type = new EnumDefinition(name); 61 | 62 | type.UnderlayingType = TypesExtractor.ExtractType(typedef.UnderlyingType) as BasicType; 63 | this.ExtractConstants(type.Constants, typedef.Fields); 64 | 65 | types.Add(name, type); 66 | } 67 | 68 | private void ExtractConstants(IDictionary dest, IEnumerable source) 69 | { 70 | source = source.Skip(1); 71 | 72 | foreach (var constdef in source) 73 | { 74 | var name = constdef.Name.Value; 75 | var value = constdef.CompileTimeValue.Value; 76 | var constant = new Constant(value); 77 | 78 | dest.Add(name, constant); 79 | } 80 | } 81 | 82 | private void ExtractInterface(Cci.INamedTypeDefinition typedef) 83 | { 84 | var name = typedef.Name.Value; 85 | var type = new InterfaceDefinition(name); 86 | 87 | this.ExtractGenericParameters(type.GenericParameters, typedef.GenericParameters); 88 | this.ExtractInterfaces(type.Interfaces, typedef.Interfaces); 89 | this.ExtractMethods(type.Methods, typedef.Methods); 90 | 91 | types.Add(name, type); 92 | } 93 | 94 | private void ExtractClass(Cci.INamedTypeDefinition typedef) 95 | { 96 | var name = typedef.Name.Value; 97 | var type = new ClassDefinition(name); 98 | Cci.ITypeReference basedef = Cci.TypeHelper.BaseClass(typedef); 99 | 100 | if (basedef == null) 101 | { 102 | basedef = host.PlatformType.SystemObject; 103 | } 104 | 105 | type.Base = TypesExtractor.ExtractType(basedef) as BasicType; 106 | 107 | this.ExtractGenericParameters(type.GenericParameters, typedef.GenericParameters); 108 | this.ExtractInterfaces(type.Interfaces, typedef.Interfaces); 109 | this.ExtractFields(type.Fields, typedef.Fields); 110 | this.ExtractMethods(type.Methods, typedef.Methods); 111 | 112 | types.Add(name, type); 113 | } 114 | 115 | private void ExtractStruct(Cci.INamedTypeDefinition typedef) 116 | { 117 | var name = typedef.Name.Value; 118 | var type = new StructDefinition(name); 119 | 120 | this.ExtractGenericParameters(type.GenericParameters, typedef.GenericParameters); 121 | this.ExtractFields(type.Fields, typedef.Fields); 122 | this.ExtractMethods(type.Methods, typedef.Methods); 123 | 124 | types.Add(name, type); 125 | } 126 | 127 | private void ExtractMethods(IDictionary dest, IEnumerable source) 128 | { 129 | foreach (var methoddef in source) 130 | { 131 | var name = methoddef.Name.Value; 132 | var type = TypesExtractor.ExtractType(methoddef.Type); 133 | var method = new MethodDefinition(name, type); 134 | 135 | this.ExtractGenericParameters(method.GenericParameters, methoddef.GenericParameters); 136 | this.ExtractParameters(method.Parameters, methoddef.Parameters); 137 | 138 | method.IsStatic = methoddef.IsStatic; 139 | method.IsConstructor = methoddef.IsConstructor; 140 | dest.Add(name, method); 141 | } 142 | } 143 | 144 | private void ExtractGenericParameters(IList dest, IEnumerable source) 145 | { 146 | foreach (var parameterdef in source) 147 | { 148 | var name = parameterdef.Name.Value; 149 | var parameter = new TypeVariable(name); 150 | 151 | dest.Add(parameter); 152 | } 153 | } 154 | 155 | private void ExtractInterfaces(IList dest, IEnumerable source) 156 | { 157 | foreach (var interfaceref in source) 158 | { 159 | var type = TypesExtractor.ExtractType(interfaceref) as BasicType; 160 | 161 | dest.Add(type); 162 | } 163 | } 164 | 165 | private void ExtractParameters(IList dest, IEnumerable source) 166 | { 167 | foreach (var parameterdef in source) 168 | { 169 | var name = parameterdef.Name.Value; 170 | var type = TypesExtractor.ExtractType(parameterdef.Type); 171 | var parameter = new LocalVariable(name, true); 172 | 173 | dest.Add(parameter); 174 | } 175 | } 176 | 177 | private void ExtractFields(IDictionary dest, IEnumerable source) 178 | { 179 | foreach (var fielddef in source) 180 | { 181 | var name = fielddef.Name.Value; 182 | var type = TypesExtractor.ExtractType(fielddef.Type); 183 | var field = new FieldDefinition(name, type); 184 | 185 | field.IsStatic = fielddef.IsStatic; 186 | dest.Add(name, field); 187 | } 188 | } 189 | } 190 | 191 | #endregion 192 | 193 | private TypesTraverser traverser; 194 | 195 | public TypesExtractor(Cci.IMetadataHost host) 196 | { 197 | this.traverser = new TypesTraverser(host); 198 | } 199 | 200 | public IDictionary Extract(Cci.IModule module) 201 | { 202 | traverser.Traverse(module); 203 | return traverser.Types; 204 | } 205 | 206 | public static IType ExtractType(Cci.ITypeReference typeref) 207 | { 208 | IType result = null; 209 | 210 | if (typeref is Cci.IArrayTypeReference) 211 | { 212 | var atyperef = typeref as Cci.IArrayTypeReference; 213 | result = TypesExtractor.ExtractType(atyperef); 214 | } 215 | else if (typeref is Cci.IPointerTypeReference) 216 | { 217 | var ptyperef = typeref as Cci.IPointerTypeReference; 218 | result = TypesExtractor.ExtractType(ptyperef); 219 | } 220 | else if (typeref is Cci.IGenericParameterReference) 221 | { 222 | var gptyperef = typeref as Cci.IGenericParameterReference; 223 | result = TypesExtractor.ExtractType(gptyperef); 224 | } 225 | else if (typeref is Cci.IGenericTypeInstanceReference) 226 | { 227 | var gtyperef = typeref as Cci.IGenericTypeInstanceReference; 228 | result = TypesExtractor.ExtractType(gtyperef); 229 | } 230 | else if (typeref is Cci.INamedTypeReference) 231 | { 232 | var ntyperef = typeref as Cci.INamedTypeReference; 233 | result = TypesExtractor.ExtractType(ntyperef); 234 | } 235 | 236 | return result; 237 | } 238 | 239 | public static ArrayType ExtractType(Cci.IArrayTypeReference typeref) 240 | { 241 | var elements = TypesExtractor.ExtractType(typeref.ElementType); 242 | var type = new ArrayType(elements); 243 | 244 | return type; 245 | } 246 | 247 | public static PointerType ExtractType(Cci.IPointerTypeReference typeref) 248 | { 249 | var target = TypesExtractor.ExtractType(typeref.TargetType); 250 | var type = new PointerType(target); 251 | 252 | return type; 253 | } 254 | 255 | public static TypeVariable ExtractType(Cci.IGenericParameterReference typeref) 256 | { 257 | var name = TypesExtractor.GetTypeName(typeref); 258 | var type = new TypeVariable(name); 259 | 260 | return type; 261 | } 262 | 263 | public static BasicType ExtractType(Cci.IGenericTypeInstanceReference typeref) 264 | { 265 | var type = TypesExtractor.ExtractType(typeref.GenericType); 266 | TypesExtractor.ExtractGenericType(type, typeref); 267 | 268 | return type; 269 | } 270 | 271 | public static BasicType ExtractType(Cci.INamedTypeReference typeref) 272 | { 273 | var name = TypesExtractor.GetTypeName(typeref); 274 | var type = new BasicType(name); 275 | 276 | return type; 277 | } 278 | 279 | private static void ExtractGenericType(BasicType type, Cci.IGenericTypeInstanceReference typeref) 280 | { 281 | foreach (var argumentref in typeref.GenericArguments) 282 | { 283 | var typearg = TypesExtractor.ExtractType(argumentref); 284 | type.GenericArguments.Add(typearg); 285 | } 286 | } 287 | 288 | private static string GetTypeName(Cci.ITypeReference typeref) 289 | { 290 | var name = Cci.TypeHelper.GetTypeName(typeref, Cci.NameFormattingOptions.OmitContainingType | Cci.NameFormattingOptions.PreserveSpecialNames); 291 | return name; 292 | } 293 | } 294 | } 295 | -------------------------------------------------------------------------------- /Backend/Utils/Exceptions.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Edgardo Zoppi. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. 2 | 3 | using Microsoft.Cci; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Text; 8 | 9 | namespace Backend.Utils 10 | { 11 | public class UnknownBytecodeException : Exception 12 | { 13 | public IOperation Opcode { get; private set; } 14 | 15 | public UnknownBytecodeException(OperationCode opcode) 16 | { 17 | this.Opcode = Opcode; 18 | } 19 | 20 | public override string Message 21 | { 22 | get { return string.Format("Unknown bytecode: {0}", this.Opcode); } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Backend/Utils/Extensions.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Edgardo Zoppi. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. 2 | 3 | using Backend.Analysis; 4 | using Backend.ThreeAddressCode; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using System.Text; 9 | using Backend.ThreeAddressCode.Values; 10 | using Backend.ThreeAddressCode.Expressions; 11 | using Backend.ThreeAddressCode.Instructions; 12 | using Backend.Visitors; 13 | using Microsoft.Cci; 14 | 15 | namespace Backend.Utils 16 | { 17 | public static class Extensions 18 | { 19 | public static bool DictionaryEquals(this IDictionary self, IDictionary other, Func valueEquals = null) 20 | { 21 | if (object.ReferenceEquals(self, other)) return true; 22 | if (self.Count != other.Count) return false; 23 | 24 | if (valueEquals == null) 25 | { 26 | valueEquals = (a, b) => object.Equals(a, b); 27 | } 28 | 29 | foreach (var key in self.Keys) 30 | { 31 | var otherContainsKey = other.ContainsKey(key); 32 | if (!otherContainsKey) return false; 33 | } 34 | 35 | foreach (var entry in self) 36 | { 37 | var value = other[entry.Key]; 38 | var valuesAreEquals = valueEquals(entry.Value, value); 39 | 40 | if (!valuesAreEquals) return false; 41 | } 42 | 43 | return true; 44 | } 45 | 46 | public static void AddRange(this ICollection collection, IEnumerable elements) 47 | { 48 | foreach (var element in elements) 49 | { 50 | collection.Add(element); 51 | } 52 | } 53 | 54 | public static MapSet ToMapSet(this IEnumerable elements, Func keySelector) 55 | { 56 | var result = new MapSet(); 57 | 58 | foreach (var element in elements) 59 | { 60 | var key = keySelector(element); 61 | result.Add(key, element); 62 | } 63 | 64 | return result; 65 | } 66 | 67 | public static MapList ToMapList(this IEnumerable elements, Func keySelector) 68 | { 69 | var result = new MapList(); 70 | 71 | foreach (var element in elements) 72 | { 73 | var key = keySelector(element); 74 | result.Add(key, element); 75 | } 76 | 77 | return result; 78 | } 79 | 80 | public static Subset ToSubset(this T[] universe) 81 | { 82 | return new Subset(universe, false); 83 | } 84 | 85 | public static Subset ToEmptySubset(this T[] universe) 86 | { 87 | return new Subset(universe, true); 88 | } 89 | 90 | public static ISet GetVariables(this IInstructionContainer block) 91 | { 92 | var result = from i in block.Instructions 93 | from v in i.Variables 94 | select v; 95 | 96 | //var result = block.Instructions.SelectMany(i => i.Variables); 97 | return new HashSet(result); 98 | } 99 | 100 | public static ISet GetModifiedVariables(this IInstructionContainer block) 101 | { 102 | var result = from i in block.Instructions 103 | from v in i.ModifiedVariables 104 | select v; 105 | 106 | //var result = block.Instructions.SelectMany(i => i.ModifiedVariables); 107 | return new HashSet(result); 108 | } 109 | 110 | public static ISet GetUsedVariables(this IInstructionContainer block) 111 | { 112 | var result = from i in block.Instructions 113 | from v in i.UsedVariables 114 | select v; 115 | 116 | //var result = block.Instructions.SelectMany(i => i.UsedVariables); 117 | return new HashSet(result); 118 | } 119 | 120 | public static ISet GetDefinedVariables(this IInstructionContainer block) 121 | { 122 | var result = from i in block.Instructions 123 | let d = i as DefinitionInstruction 124 | where d != null && d.HasResult 125 | select d.Result; 126 | 127 | return new HashSet(result); 128 | //var result = new HashSet(); 129 | 130 | //foreach (var instruction in block.Instructions) 131 | //{ 132 | // var definition = instruction as DefinitionInstruction; 133 | 134 | // if (definition != null && definition.HasResult) 135 | // { 136 | // result.Add(definition.Result); 137 | // } 138 | //} 139 | 140 | //return result; 141 | } 142 | 143 | public static ISet GetModifiedVariables(this CFGLoop loop) 144 | { 145 | var result = from n in loop.Body 146 | from v in n.GetModifiedVariables() 147 | select v; 148 | 149 | //var result = loop.Body.SelectMany(n => n.GetModifiedVariables()); 150 | return new HashSet(result); 151 | } 152 | 153 | public static ISet GetVariables(this ControlFlowGraph cfg) 154 | { 155 | var result = from n in cfg.Nodes 156 | from v in n.GetVariables() 157 | select v; 158 | 159 | //var result = cfg.Nodes.SelectMany(n => n.GetVariables()); 160 | return new HashSet(result); 161 | } 162 | 163 | public static ISet GetExitNodes(this CFGLoop loop) 164 | { 165 | var result = from n in loop.Body 166 | from m in n.Successors 167 | where !loop.Body.Contains(m) 168 | select n; 169 | 170 | //var result = loop.Body.Where(n => n.Successors.Any(m => !loop.Body.Contains(m))); 171 | return new HashSet(result); 172 | } 173 | 174 | public static IExpression ToExpression(this IValue value) 175 | { 176 | return value as IExpression; 177 | } 178 | 179 | //public static IExpression GetValueOriginal(this IDictionary equalities, IVariable variable) 180 | //{ 181 | // var result = equalities.ContainsKey(variable) ? equalities[variable] : variable; 182 | // return result; 183 | //} 184 | 185 | public static IExpression GetValue(this IDictionary equalities, IVariable variable) 186 | { 187 | IExpression result = variable; 188 | 189 | while (variable != null && equalities.ContainsKey(variable)) 190 | { 191 | result = equalities[variable]; 192 | variable = result as IVariable; 193 | } 194 | 195 | return result; 196 | } 197 | 198 | public static bool IsTemporal(this IVariable variable) 199 | { 200 | while (variable is DerivedVariable) 201 | { 202 | var derived = variable as DerivedVariable; 203 | variable = derived.Original; 204 | } 205 | 206 | var result = variable is TemporalVariable; 207 | return result; 208 | } 209 | 210 | public static bool IsCopy(this Instruction instruction, out IVariable left, out IVariable right) 211 | { 212 | var result = false; 213 | left = null; 214 | right = null; 215 | 216 | if (instruction is LoadInstruction) 217 | { 218 | var load = instruction as LoadInstruction; 219 | 220 | if (load.Operand is IVariable) 221 | { 222 | left = load.Result; 223 | right = load.Operand as IVariable; 224 | result = true; 225 | } 226 | } 227 | 228 | return result; 229 | } 230 | 231 | public static IExpression ReplaceVariables(this IExpression expr, IDictionary equalities) where T : IExpression 232 | { 233 | foreach (var variable in expr.Variables) 234 | { 235 | if (variable.IsTemporal()) 236 | { 237 | var hasValue = equalities.ContainsKey(variable); 238 | 239 | if (hasValue) 240 | { 241 | var value = equalities[variable]; 242 | var isUnknown = value is UnknownValue; 243 | var isPhi = value is PhiExpression; 244 | var isMethodCall = value is MethodCallExpression; 245 | 246 | if (isUnknown || isPhi || isMethodCall) 247 | continue; 248 | 249 | expr = expr.Replace(variable, value); 250 | } 251 | } 252 | } 253 | 254 | return expr; 255 | } 256 | 257 | public static void RemoveTemporalVariables(this PointsToGraph ptg) 258 | { 259 | var temporals = ptg.Variables.OfType().ToArray(); 260 | 261 | foreach (var temporal in temporals) 262 | { 263 | ptg.Remove(temporal); 264 | } 265 | } 266 | 267 | public static bool IsPure(this IMethodReference method) 268 | { 269 | var result = method.Attributes.Any(a => a.Type == Types.Instance.PureAttributeType); 270 | 271 | if (!result) 272 | { 273 | result = method.Name.Value == "get_Count" && Types.Instance.IsContainer(method.ContainingType); 274 | } 275 | 276 | return result; 277 | } 278 | } 279 | } 280 | -------------------------------------------------------------------------------- /Backend/Utils/Map.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Edgardo Zoppi. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. 2 | 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | 8 | namespace Backend.Utils 9 | { 10 | public class Map : Dictionary 11 | where TCollection : ICollection, new() 12 | { 13 | public void Add(TKey key) 14 | { 15 | this.AddKeyAndGetValues(key); 16 | } 17 | 18 | public void Add(TKey key, TValue value) 19 | { 20 | var collection = this.AddKeyAndGetValues(key); 21 | collection.Add(value); 22 | } 23 | 24 | public void AddRange(TKey key, IEnumerable values) 25 | { 26 | var collection = this.AddKeyAndGetValues(key); 27 | collection.AddRange(values); 28 | } 29 | 30 | private TCollection AddKeyAndGetValues(TKey key) 31 | { 32 | TCollection result; 33 | 34 | if (this.ContainsKey(key)) 35 | { 36 | result = this[key]; 37 | } 38 | else 39 | { 40 | result = new TCollection(); 41 | this.Add(key, result); 42 | } 43 | 44 | return result; 45 | } 46 | } 47 | 48 | public class MapSet : Map> 49 | { 50 | public bool MapEquals(MapSet other) 51 | { 52 | Func, ISet, bool> setEquals = (a, b) => a.SetEquals(b); 53 | return this.DictionaryEquals(other, setEquals); 54 | } 55 | } 56 | 57 | public class MapList : Map> 58 | { 59 | public bool MapEquals(MapList other) 60 | { 61 | Func, IList, bool> listEquals = (a, b) => a.SequenceEqual(b); 62 | return this.DictionaryEquals(other, listEquals); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Backend/Utils/OperationHelper.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Edgardo Zoppi. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. 2 | 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using Backend.ThreeAddressCode.Instructions; 8 | using Microsoft.Cci; 9 | 10 | namespace Backend.Utils 11 | { 12 | public static class OperationHelper 13 | { 14 | public static ConvertOperation ToConvertOperation(OperationCode opcode) 15 | { 16 | switch (opcode) 17 | { 18 | case OperationCode.Castclass: 19 | case OperationCode.Isinst: return ConvertOperation.Cast; 20 | case OperationCode.Box: return ConvertOperation.Box; 21 | case OperationCode.Unbox: return ConvertOperation.UnboxPtr; 22 | case OperationCode.Unbox_Any: return ConvertOperation.Unbox; 23 | case OperationCode.Conv_I: 24 | case OperationCode.Conv_Ovf_I: 25 | case OperationCode.Conv_Ovf_I_Un: 26 | case OperationCode.Conv_I1: 27 | case OperationCode.Conv_Ovf_I1: 28 | case OperationCode.Conv_Ovf_I1_Un: 29 | case OperationCode.Conv_I2: 30 | case OperationCode.Conv_Ovf_I2: 31 | case OperationCode.Conv_Ovf_I2_Un: 32 | case OperationCode.Conv_I4: 33 | case OperationCode.Conv_Ovf_I4: 34 | case OperationCode.Conv_Ovf_I4_Un: 35 | case OperationCode.Conv_I8: 36 | case OperationCode.Conv_Ovf_I8: 37 | case OperationCode.Conv_Ovf_I8_Un: 38 | case OperationCode.Conv_U: 39 | case OperationCode.Conv_Ovf_U: 40 | case OperationCode.Conv_Ovf_U_Un: 41 | case OperationCode.Conv_U1: 42 | case OperationCode.Conv_Ovf_U1: 43 | case OperationCode.Conv_Ovf_U1_Un: 44 | case OperationCode.Conv_U2: 45 | case OperationCode.Conv_Ovf_U2: 46 | case OperationCode.Conv_Ovf_U2_Un: 47 | case OperationCode.Conv_U4: 48 | case OperationCode.Conv_Ovf_U4: 49 | case OperationCode.Conv_Ovf_U4_Un: 50 | case OperationCode.Conv_U8: 51 | case OperationCode.Conv_Ovf_U8: 52 | case OperationCode.Conv_Ovf_U8_Un: 53 | case OperationCode.Conv_R4: 54 | case OperationCode.Conv_R8: 55 | case OperationCode.Conv_R_Un: return ConvertOperation.Conv; 56 | 57 | default: throw new UnknownBytecodeException(opcode); 58 | } 59 | } 60 | 61 | public static BranchOperation ToBranchOperation(OperationCode opcode) 62 | { 63 | switch (opcode) 64 | { 65 | case OperationCode.Beq: 66 | case OperationCode.Beq_S: return BranchOperation.Eq; 67 | case OperationCode.Bne_Un: 68 | case OperationCode.Bne_Un_S: return BranchOperation.Neq; 69 | case OperationCode.Bge: 70 | case OperationCode.Bge_S: 71 | case OperationCode.Bge_Un: 72 | case OperationCode.Bge_Un_S: return BranchOperation.Ge; 73 | case OperationCode.Bgt: 74 | case OperationCode.Bgt_S: 75 | case OperationCode.Bgt_Un: 76 | case OperationCode.Bgt_Un_S: return BranchOperation.Gt; 77 | case OperationCode.Ble: 78 | case OperationCode.Ble_S: 79 | case OperationCode.Ble_Un: 80 | case OperationCode.Ble_Un_S: return BranchOperation.Le; 81 | case OperationCode.Blt: 82 | case OperationCode.Blt_S: 83 | case OperationCode.Blt_Un: 84 | case OperationCode.Blt_Un_S: return BranchOperation.Lt; 85 | 86 | default: throw new UnknownBytecodeException(opcode); 87 | } 88 | } 89 | 90 | public static UnaryOperation ToUnaryOperation(OperationCode opcode) 91 | { 92 | switch (opcode) 93 | { 94 | case OperationCode.Neg: return UnaryOperation.Neg; 95 | case OperationCode.Not: return UnaryOperation.Not; 96 | 97 | default: throw new UnknownBytecodeException(opcode); 98 | } 99 | } 100 | 101 | public static BinaryOperation ToBinaryOperation(OperationCode opcode) 102 | { 103 | switch (opcode) 104 | { 105 | case OperationCode.Add: 106 | case OperationCode.Add_Ovf: 107 | case OperationCode.Add_Ovf_Un: return BinaryOperation.Add; 108 | case OperationCode.And: return BinaryOperation.And; 109 | case OperationCode.Ceq: return BinaryOperation.Eq; 110 | case OperationCode.Cgt: 111 | case OperationCode.Cgt_Un: return BinaryOperation.Gt; 112 | case OperationCode.Clt: 113 | case OperationCode.Clt_Un: return BinaryOperation.Lt; 114 | case OperationCode.Div: 115 | case OperationCode.Div_Un: return BinaryOperation.Div; 116 | case OperationCode.Mul: 117 | case OperationCode.Mul_Ovf: 118 | case OperationCode.Mul_Ovf_Un: return BinaryOperation.Mul; 119 | case OperationCode.Or: return BinaryOperation.Or; 120 | case OperationCode.Rem: 121 | case OperationCode.Rem_Un: return BinaryOperation.Rem; 122 | case OperationCode.Shl: return BinaryOperation.Shl; 123 | case OperationCode.Shr: 124 | case OperationCode.Shr_Un: return BinaryOperation.Shr; 125 | case OperationCode.Sub: 126 | case OperationCode.Sub_Ovf: 127 | case OperationCode.Sub_Ovf_Un: return BinaryOperation.Sub; 128 | case OperationCode.Xor: return BinaryOperation.Xor; 129 | 130 | default: throw new UnknownBytecodeException(opcode); 131 | } 132 | } 133 | 134 | public static ITypeReference GetOperationType(OperationCode opcode) 135 | { 136 | switch (opcode) 137 | { 138 | case OperationCode.Ldind_I: 139 | case OperationCode.Stind_I: 140 | case OperationCode.Stelem_I: 141 | case OperationCode.Conv_I: 142 | case OperationCode.Conv_Ovf_I: 143 | case OperationCode.Conv_Ovf_I_Un: return Types.Instance.PlatformType.SystemIntPtr; 144 | case OperationCode.Ldind_I1: 145 | case OperationCode.Stind_I1: 146 | case OperationCode.Stelem_I1: 147 | case OperationCode.Conv_I1: 148 | case OperationCode.Conv_Ovf_I1: 149 | case OperationCode.Conv_Ovf_I1_Un: return Types.Instance.PlatformType.SystemInt8; 150 | case OperationCode.Ldind_I2: 151 | case OperationCode.Stind_I2: 152 | case OperationCode.Stelem_I2: 153 | case OperationCode.Conv_I2: 154 | case OperationCode.Conv_Ovf_I2: 155 | case OperationCode.Conv_Ovf_I2_Un: return Types.Instance.PlatformType.SystemInt16; 156 | case OperationCode.Ldc_I4: 157 | case OperationCode.Ldc_I4_0: 158 | case OperationCode.Ldc_I4_1: 159 | case OperationCode.Ldc_I4_2: 160 | case OperationCode.Ldc_I4_3: 161 | case OperationCode.Ldc_I4_4: 162 | case OperationCode.Ldc_I4_5: 163 | case OperationCode.Ldc_I4_6: 164 | case OperationCode.Ldc_I4_7: 165 | case OperationCode.Ldc_I4_8: 166 | case OperationCode.Ldc_I4_M1: 167 | case OperationCode.Ldc_I4_S: 168 | case OperationCode.Ldind_I4: 169 | case OperationCode.Stind_I4: 170 | case OperationCode.Stelem_I4: 171 | case OperationCode.Conv_I4: 172 | case OperationCode.Conv_Ovf_I4: 173 | case OperationCode.Conv_Ovf_I4_Un: return Types.Instance.PlatformType.SystemInt32; 174 | case OperationCode.Ldc_I8: 175 | case OperationCode.Ldind_I8: 176 | case OperationCode.Stind_I8: 177 | case OperationCode.Stelem_I8: 178 | case OperationCode.Conv_I8: 179 | case OperationCode.Conv_Ovf_I8: 180 | case OperationCode.Conv_Ovf_I8_Un: return Types.Instance.PlatformType.SystemInt64; 181 | case OperationCode.Conv_U: 182 | case OperationCode.Conv_Ovf_U: 183 | case OperationCode.Conv_Ovf_U_Un: 184 | case OperationCode.Ldlen: return Types.Instance.PlatformType.SystemUIntPtr; 185 | case OperationCode.Ldind_U1: 186 | case OperationCode.Conv_U1: 187 | case OperationCode.Conv_Ovf_U1: 188 | case OperationCode.Conv_Ovf_U1_Un: return Types.Instance.PlatformType.SystemUInt8; 189 | case OperationCode.Ldind_U2: 190 | case OperationCode.Conv_U2: 191 | case OperationCode.Conv_Ovf_U2: 192 | case OperationCode.Conv_Ovf_U2_Un: return Types.Instance.PlatformType.SystemUInt16; 193 | case OperationCode.Ldind_U4: 194 | case OperationCode.Conv_U4: 195 | case OperationCode.Conv_Ovf_U4: 196 | case OperationCode.Conv_Ovf_U4_Un: 197 | case OperationCode.Sizeof: return Types.Instance.PlatformType.SystemUInt32; 198 | case OperationCode.Conv_U8: 199 | case OperationCode.Conv_Ovf_U8: 200 | case OperationCode.Conv_Ovf_U8_Un: return Types.Instance.PlatformType.SystemUInt64; 201 | case OperationCode.Ldc_R4: 202 | case OperationCode.Ldind_R4: 203 | case OperationCode.Stind_R4: 204 | case OperationCode.Stelem_R4: 205 | case OperationCode.Conv_R4: return Types.Instance.PlatformType.SystemFloat32; 206 | case OperationCode.Ldc_R8: 207 | case OperationCode.Ldind_R8: 208 | case OperationCode.Stind_R8: 209 | case OperationCode.Stelem_R8: 210 | case OperationCode.Conv_R8: 211 | case OperationCode.Conv_R_Un: return Types.Instance.PlatformType.SystemFloat64; 212 | case OperationCode.Ldnull: return Types.Instance.PlatformType.SystemObject; 213 | case OperationCode.Ldstr: return Types.Instance.PlatformType.SystemString; 214 | 215 | default: return null; 216 | } 217 | } 218 | 219 | public static bool GetUnaryConditionalBranchValue(OperationCode opcode) 220 | { 221 | switch (opcode) 222 | { 223 | case OperationCode.Brfalse: 224 | case OperationCode.Brfalse_S: return false; 225 | case OperationCode.Brtrue: 226 | case OperationCode.Brtrue_S: return true; 227 | 228 | default: throw new UnknownBytecodeException(opcode); 229 | } 230 | } 231 | 232 | public static bool OperandsAreUnsigned(OperationCode opcode) 233 | { 234 | switch (opcode) 235 | { 236 | case OperationCode.Add_Ovf_Un: 237 | case OperationCode.Bge_Un: 238 | case OperationCode.Bge_Un_S: 239 | case OperationCode.Bgt_Un: 240 | case OperationCode.Bgt_Un_S: 241 | case OperationCode.Ble_Un: 242 | case OperationCode.Ble_Un_S: 243 | case OperationCode.Blt_Un: 244 | case OperationCode.Blt_Un_S: 245 | case OperationCode.Bne_Un: 246 | case OperationCode.Bne_Un_S: 247 | case OperationCode.Cgt_Un: 248 | case OperationCode.Clt_Un: 249 | case OperationCode.Conv_Ovf_I1_Un: 250 | case OperationCode.Conv_Ovf_I2_Un: 251 | case OperationCode.Conv_Ovf_I4_Un: 252 | case OperationCode.Conv_Ovf_I8_Un: 253 | case OperationCode.Conv_Ovf_I_Un: 254 | case OperationCode.Conv_Ovf_U1_Un: 255 | case OperationCode.Conv_Ovf_U2_Un: 256 | case OperationCode.Conv_Ovf_U4_Un: 257 | case OperationCode.Conv_Ovf_U8_Un: 258 | case OperationCode.Conv_Ovf_U_Un: 259 | case OperationCode.Conv_R_Un: 260 | case OperationCode.Div_Un: 261 | case OperationCode.Mul_Ovf_Un: 262 | case OperationCode.Rem_Un: 263 | case OperationCode.Shr_Un: 264 | case OperationCode.Sub_Ovf_Un: return true; 265 | 266 | default: return false; 267 | } 268 | } 269 | 270 | public static bool PerformsOverflowCheck(OperationCode opcode) 271 | { 272 | switch (opcode) 273 | { 274 | case OperationCode.Add_Ovf: 275 | case OperationCode.Add_Ovf_Un: 276 | case OperationCode.Conv_Ovf_I: 277 | case OperationCode.Conv_Ovf_I1: 278 | case OperationCode.Conv_Ovf_I1_Un: 279 | case OperationCode.Conv_Ovf_I2: 280 | case OperationCode.Conv_Ovf_I2_Un: 281 | case OperationCode.Conv_Ovf_I4: 282 | case OperationCode.Conv_Ovf_I4_Un: 283 | case OperationCode.Conv_Ovf_I8: 284 | case OperationCode.Conv_Ovf_I8_Un: 285 | case OperationCode.Conv_Ovf_I_Un: 286 | case OperationCode.Conv_Ovf_U: 287 | case OperationCode.Conv_Ovf_U1: 288 | case OperationCode.Conv_Ovf_U1_Un: 289 | case OperationCode.Conv_Ovf_U2: 290 | case OperationCode.Conv_Ovf_U2_Un: 291 | case OperationCode.Conv_Ovf_U4: 292 | case OperationCode.Conv_Ovf_U4_Un: 293 | case OperationCode.Conv_Ovf_U8: 294 | case OperationCode.Conv_Ovf_U8_Un: 295 | case OperationCode.Conv_Ovf_U_Un: 296 | case OperationCode.Mul_Ovf: 297 | case OperationCode.Mul_Ovf_Un: 298 | case OperationCode.Sub_Ovf: 299 | case OperationCode.Sub_Ovf_Un: return true; 300 | 301 | default: return false; 302 | } 303 | } 304 | 305 | public static bool CanFallThroughNextOperation(OperationCode opcode) 306 | { 307 | switch (opcode) 308 | { 309 | case OperationCode.Ret: 310 | case OperationCode.Endfinally: 311 | case OperationCode.Endfilter: 312 | case OperationCode.Throw: 313 | case OperationCode.Rethrow: 314 | case OperationCode.Br: 315 | case OperationCode.Br_S: 316 | case OperationCode.Leave: 317 | case OperationCode.Leave_S: return false; 318 | 319 | default: return true; 320 | } 321 | } 322 | 323 | public static bool IsBranch(OperationCode opcode) 324 | { 325 | switch (opcode) 326 | { 327 | case OperationCode.Br: 328 | case OperationCode.Br_S: 329 | case OperationCode.Leave: 330 | case OperationCode.Leave_S: 331 | case OperationCode.Beq: 332 | case OperationCode.Beq_S: 333 | case OperationCode.Bne_Un: 334 | case OperationCode.Bne_Un_S: 335 | case OperationCode.Bge: 336 | case OperationCode.Bge_S: 337 | case OperationCode.Bge_Un: 338 | case OperationCode.Bge_Un_S: 339 | case OperationCode.Bgt: 340 | case OperationCode.Bgt_S: 341 | case OperationCode.Bgt_Un: 342 | case OperationCode.Bgt_Un_S: 343 | case OperationCode.Ble: 344 | case OperationCode.Ble_S: 345 | case OperationCode.Ble_Un: 346 | case OperationCode.Ble_Un_S: 347 | case OperationCode.Blt: 348 | case OperationCode.Blt_S: 349 | case OperationCode.Blt_Un: 350 | case OperationCode.Blt_Un_S: 351 | case OperationCode.Brfalse: 352 | case OperationCode.Brfalse_S: 353 | case OperationCode.Brtrue: 354 | case OperationCode.Brtrue_S: 355 | case OperationCode.Switch: return true; 356 | 357 | default: return false; 358 | } 359 | } 360 | } 361 | } 362 | -------------------------------------------------------------------------------- /Backend/Utils/Subset.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Edgardo Zoppi. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. 2 | 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Collections; 8 | 9 | namespace Backend.Utils 10 | { 11 | public class Subset 12 | { 13 | private T[] universe; 14 | private BitArray data; 15 | 16 | public Subset(T[] universe, bool empty = true) 17 | { 18 | this.universe = universe; 19 | this.data = new BitArray(universe.Length, !empty); 20 | } 21 | 22 | public Subset(Subset subset) 23 | { 24 | this.universe = subset.universe; 25 | this.data = new BitArray(subset.data); 26 | } 27 | 28 | public T[] Universe 29 | { 30 | get { return this.universe; } 31 | } 32 | 33 | public bool IsMember(int index) 34 | { 35 | return this.data[index]; 36 | } 37 | 38 | public Subset Clone() 39 | { 40 | return new Subset(this); 41 | } 42 | 43 | public void Clear() 44 | { 45 | this.data.SetAll(false); 46 | } 47 | 48 | public void AddAll() 49 | { 50 | this.data.SetAll(true); 51 | } 52 | 53 | public void Add(int index) 54 | { 55 | this.data[index] = true; 56 | } 57 | 58 | public void Remove(int index) 59 | { 60 | this.data[index] = false; 61 | } 62 | 63 | public void Complement() 64 | { 65 | this.data.Not(); 66 | } 67 | 68 | public void Union(Subset subset) 69 | { 70 | this.data.Or(subset.data); 71 | } 72 | 73 | public void Intersect(Subset subset) 74 | { 75 | this.data.And(subset.data); 76 | } 77 | 78 | public void Except(Subset subset) 79 | { 80 | subset.data.Not(); 81 | this.data.And(subset.data); 82 | subset.data.Not(); 83 | } 84 | 85 | public void SymmetricExcept(Subset subset) 86 | { 87 | this.data.Xor(subset.data); 88 | } 89 | 90 | public ISet ToSet() 91 | { 92 | var set = new HashSet(); 93 | this.ToSet(set); 94 | return set; 95 | } 96 | 97 | public void ToSet(ISet set) 98 | { 99 | set.Clear(); 100 | 101 | for (var i = 0; i < this.universe.Length; ++i) 102 | { 103 | var isMember = this.data[i]; 104 | 105 | if (isMember) 106 | { 107 | var element = this.universe[i]; 108 | set.Add(element); 109 | } 110 | } 111 | } 112 | 113 | public override int GetHashCode() 114 | { 115 | return this.data.GetHashCode(); 116 | } 117 | 118 | public override bool Equals(object other) 119 | { 120 | var subset = other as Subset; 121 | 122 | if (subset == null || 123 | this.universe.Length != subset.universe.Length) 124 | return false; 125 | 126 | for (var i = 0; i < this.universe.Length; ++i) 127 | { 128 | if (this.data[i] != subset.data[i]) 129 | return false; 130 | } 131 | 132 | return true; 133 | } 134 | 135 | public override string ToString() 136 | { 137 | var sb = new StringBuilder(" "); 138 | 139 | for (var i = 0; i < this.universe.Length; ++i) 140 | { 141 | var isMember = this.data[i]; 142 | 143 | if (isMember) 144 | { 145 | var element = this.universe[i]; 146 | sb.AppendFormat("{0} ", element); 147 | } 148 | } 149 | 150 | return sb.ToString(); 151 | } 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /Backend/Visitors/IInstructionVisitor.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Edgardo Zoppi. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. 2 | 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using Backend.ThreeAddressCode.Instructions; 8 | 9 | namespace Backend.Visitors 10 | { 11 | public interface IInstructionContainer 12 | { 13 | IList Instructions { get; } 14 | } 15 | 16 | public interface IInstructionVisitor 17 | { 18 | void Visit(IInstructionContainer container); 19 | void Visit(Instruction instruction); 20 | void Visit(DefinitionInstruction instruction); 21 | void Visit(BinaryInstruction instruction); 22 | void Visit(UnaryInstruction instruction); 23 | void Visit(LoadInstruction instruction); 24 | void Visit(StoreInstruction instruction); 25 | void Visit(NopInstruction instruction); 26 | void Visit(BreakpointInstruction instruction); 27 | void Visit(TryInstruction instruction); 28 | void Visit(FaultInstruction instruction); 29 | void Visit(FinallyInstruction instruction); 30 | void Visit(CatchInstruction instruction); 31 | void Visit(ConvertInstruction instruction); 32 | void Visit(ReturnInstruction instruction); 33 | void Visit(ThrowInstruction instruction); 34 | void Visit(BranchInstruction instruction); 35 | void Visit(ExceptionalBranchInstruction instruction); 36 | void Visit(UnconditionalBranchInstruction instruction); 37 | void Visit(ConditionalBranchInstruction instruction); 38 | void Visit(SwitchInstruction instruction); 39 | void Visit(SizeofInstruction instruction); 40 | void Visit(LoadTokenInstruction instruction); 41 | void Visit(MethodCallInstruction instruction); 42 | void Visit(IndirectMethodCallInstruction instruction); 43 | void Visit(CreateObjectInstruction instruction); 44 | void Visit(CopyMemoryInstruction instruction); 45 | void Visit(LocalAllocationInstruction instruction); 46 | void Visit(InitializeMemoryInstruction instruction); 47 | void Visit(InitializeObjectInstruction instruction); 48 | void Visit(CopyObjectInstruction instruction); 49 | void Visit(CreateArrayInstruction instruction); 50 | void Visit(PhiInstruction instruction); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Backend/Visitors/InstructionVisitor.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Edgardo Zoppi. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. 2 | 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using Backend.ThreeAddressCode.Instructions; 8 | 9 | namespace Backend.Visitors 10 | { 11 | public abstract class InstructionVisitor : IInstructionVisitor 12 | { 13 | public virtual void Visit(IInstructionContainer container) 14 | { 15 | foreach (var instruction in container.Instructions) 16 | { 17 | instruction.Accept(this); 18 | } 19 | } 20 | 21 | public virtual void Visit(Instruction instruction) { } 22 | public virtual void Visit(DefinitionInstruction instruction) { } 23 | public virtual void Visit(BinaryInstruction instruction) { } 24 | public virtual void Visit(UnaryInstruction instruction) { } 25 | public virtual void Visit(LoadInstruction instruction) { } 26 | public virtual void Visit(StoreInstruction instruction) { } 27 | public virtual void Visit(NopInstruction instruction) { } 28 | public virtual void Visit(BreakpointInstruction instruction) { } 29 | public virtual void Visit(TryInstruction instruction) { } 30 | public virtual void Visit(FaultInstruction instruction) { } 31 | public virtual void Visit(FinallyInstruction instruction) { } 32 | public virtual void Visit(CatchInstruction instruction) { } 33 | public virtual void Visit(ConvertInstruction instruction) { } 34 | public virtual void Visit(ReturnInstruction instruction) { } 35 | public virtual void Visit(ThrowInstruction instruction) { } 36 | public virtual void Visit(BranchInstruction instruction) { } 37 | public virtual void Visit(ExceptionalBranchInstruction instruction) { } 38 | public virtual void Visit(UnconditionalBranchInstruction instruction) { } 39 | public virtual void Visit(ConditionalBranchInstruction instruction) { } 40 | public virtual void Visit(SwitchInstruction instruction) { } 41 | public virtual void Visit(SizeofInstruction instruction) { } 42 | public virtual void Visit(LoadTokenInstruction instruction) { } 43 | public virtual void Visit(MethodCallInstruction instruction) { } 44 | public virtual void Visit(IndirectMethodCallInstruction instruction) { } 45 | public virtual void Visit(CreateObjectInstruction instruction) { } 46 | public virtual void Visit(CopyMemoryInstruction instruction) { } 47 | public virtual void Visit(LocalAllocationInstruction instruction) { } 48 | public virtual void Visit(InitializeMemoryInstruction instruction) { } 49 | public virtual void Visit(InitializeObjectInstruction instruction) { } 50 | public virtual void Visit(CopyObjectInstruction instruction) { } 51 | public virtual void Visit(CreateArrayInstruction instruction) { } 52 | public virtual void Visit(PhiInstruction instruction) { } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /CCI Backend.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual Studio 2010 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Console", "Console\Console.csproj", "{C836D6AD-2A48-4FFF-A958-023C48A65478}" 5 | ProjectSection(ProjectDependencies) = postProject 6 | {A7EFFB71-0EE7-413C-85C8-5C74C8D4CDB0} = {A7EFFB71-0EE7-413C-85C8-5C74C8D4CDB0} 7 | EndProjectSection 8 | EndProject 9 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Backend", "Backend\Backend.csproj", "{45C7B613-E32D-43E8-8030-932D509602EB}" 10 | EndProject 11 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test", "Test\Test.csproj", "{A7EFFB71-0EE7-413C-85C8-5C74C8D4CDB0}" 12 | EndProject 13 | Global 14 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 15 | Debug|Any CPU = Debug|Any CPU 16 | Debug|Mixed Platforms = Debug|Mixed Platforms 17 | Debug|x86 = Debug|x86 18 | Release|Any CPU = Release|Any CPU 19 | Release|Mixed Platforms = Release|Mixed Platforms 20 | Release|x86 = Release|x86 21 | EndGlobalSection 22 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 23 | {C836D6AD-2A48-4FFF-A958-023C48A65478}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 24 | {C836D6AD-2A48-4FFF-A958-023C48A65478}.Debug|Any CPU.Build.0 = Debug|Any CPU 25 | {C836D6AD-2A48-4FFF-A958-023C48A65478}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU 26 | {C836D6AD-2A48-4FFF-A958-023C48A65478}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU 27 | {C836D6AD-2A48-4FFF-A958-023C48A65478}.Debug|x86.ActiveCfg = Debug|Any CPU 28 | {C836D6AD-2A48-4FFF-A958-023C48A65478}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {C836D6AD-2A48-4FFF-A958-023C48A65478}.Release|Any CPU.Build.0 = Release|Any CPU 30 | {C836D6AD-2A48-4FFF-A958-023C48A65478}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU 31 | {C836D6AD-2A48-4FFF-A958-023C48A65478}.Release|Mixed Platforms.Build.0 = Release|Any CPU 32 | {C836D6AD-2A48-4FFF-A958-023C48A65478}.Release|x86.ActiveCfg = Release|Any CPU 33 | {45C7B613-E32D-43E8-8030-932D509602EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 34 | {45C7B613-E32D-43E8-8030-932D509602EB}.Debug|Any CPU.Build.0 = Debug|Any CPU 35 | {45C7B613-E32D-43E8-8030-932D509602EB}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU 36 | {45C7B613-E32D-43E8-8030-932D509602EB}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU 37 | {45C7B613-E32D-43E8-8030-932D509602EB}.Debug|x86.ActiveCfg = Debug|Any CPU 38 | {45C7B613-E32D-43E8-8030-932D509602EB}.Release|Any CPU.ActiveCfg = Release|Any CPU 39 | {45C7B613-E32D-43E8-8030-932D509602EB}.Release|Any CPU.Build.0 = Release|Any CPU 40 | {45C7B613-E32D-43E8-8030-932D509602EB}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU 41 | {45C7B613-E32D-43E8-8030-932D509602EB}.Release|Mixed Platforms.Build.0 = Release|Any CPU 42 | {45C7B613-E32D-43E8-8030-932D509602EB}.Release|x86.ActiveCfg = Release|Any CPU 43 | {A7EFFB71-0EE7-413C-85C8-5C74C8D4CDB0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 44 | {A7EFFB71-0EE7-413C-85C8-5C74C8D4CDB0}.Debug|Any CPU.Build.0 = Debug|Any CPU 45 | {A7EFFB71-0EE7-413C-85C8-5C74C8D4CDB0}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU 46 | {A7EFFB71-0EE7-413C-85C8-5C74C8D4CDB0}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU 47 | {A7EFFB71-0EE7-413C-85C8-5C74C8D4CDB0}.Debug|x86.ActiveCfg = Debug|Any CPU 48 | {A7EFFB71-0EE7-413C-85C8-5C74C8D4CDB0}.Release|Any CPU.ActiveCfg = Release|Any CPU 49 | {A7EFFB71-0EE7-413C-85C8-5C74C8D4CDB0}.Release|Any CPU.Build.0 = Release|Any CPU 50 | {A7EFFB71-0EE7-413C-85C8-5C74C8D4CDB0}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU 51 | {A7EFFB71-0EE7-413C-85C8-5C74C8D4CDB0}.Release|Mixed Platforms.Build.0 = Release|Any CPU 52 | {A7EFFB71-0EE7-413C-85C8-5C74C8D4CDB0}.Release|x86.ActiveCfg = Release|Any CPU 53 | EndGlobalSection 54 | GlobalSection(SolutionProperties) = preSolution 55 | HideSolutionNode = FALSE 56 | EndGlobalSection 57 | EndGlobal 58 | -------------------------------------------------------------------------------- /Console/Assembly.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Edgardo Zoppi. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. 2 | 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.IO; 8 | using Microsoft.Cci; 9 | using Microsoft.Cci.MutableCodeModel; 10 | 11 | namespace Console 12 | { 13 | public class Assembly : IDisposable 14 | { 15 | public string FileName { get; private set; } 16 | public bool IsLoaded { get; private set; } 17 | public IMetadataHost Host { get; private set; } 18 | public IModule Module { get; private set; } 19 | public PdbReader PdbReader { get; private set; } 20 | 21 | public Assembly(IMetadataHost host) 22 | { 23 | this.Host = host; 24 | } 25 | 26 | public Assembly(IMetadataHost host, IModule module) 27 | { 28 | this.Host = host; 29 | this.Module = module; 30 | this.IsLoaded = true; 31 | } 32 | 33 | public void Load(string fileName) 34 | { 35 | this.Module = this.Host.LoadUnitFrom(fileName) as IModule; 36 | 37 | if (this.Module == null || this.Module == Dummy.Module || this.Module == Dummy.Assembly) 38 | throw new Exception("The input is not a valid CLR module or assembly."); 39 | 40 | var pdbFileName = Path.ChangeExtension(fileName, "pdb"); 41 | 42 | if (File.Exists(pdbFileName)) 43 | { 44 | using (var pdbStream = File.OpenRead(pdbFileName)) 45 | this.PdbReader = new PdbReader(pdbStream, this.Host); 46 | } 47 | 48 | this.FileName = fileName; 49 | this.IsLoaded = true; 50 | } 51 | 52 | public void Save(string fileName) 53 | { 54 | var pdbName = Path.ChangeExtension(fileName, "pdb"); 55 | 56 | using (var peStream = File.Create(fileName)) 57 | { 58 | if (this.PdbReader == null) 59 | { 60 | PeWriter.WritePeToStream(this.Module, this.Host, peStream); 61 | } 62 | else 63 | { 64 | using (var pdbWriter = new PdbWriter(pdbName, this.PdbReader)) 65 | PeWriter.WritePeToStream(this.Module, this.Host, peStream, this.PdbReader, this.PdbReader, pdbWriter); 66 | } 67 | } 68 | } 69 | 70 | public void Unload() 71 | { 72 | if (!this.IsLoaded) return; 73 | 74 | if (this.PdbReader != null) 75 | { 76 | this.PdbReader.Dispose(); 77 | this.PdbReader = null; 78 | } 79 | 80 | this.Module = null; 81 | this.FileName = null; 82 | this.IsLoaded = false; 83 | } 84 | 85 | public void Dispose() 86 | { 87 | this.Unload(); 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /Console/Console.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | x86 6 | 8.0.30703 7 | 2.0 8 | {C836D6AD-2A48-4FFF-A958-023C48A65478} 9 | Exe 10 | Properties 11 | Console 12 | Console 13 | v4.0 14 | 15 | 16 | 512 17 | 18 | 19 | true 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | full 23 | AnyCPU 24 | prompt 25 | MinimumRecommendedRules.ruleset 26 | 27 | 28 | bin\Release\ 29 | TRACE 30 | true 31 | pdbonly 32 | AnyCPU 33 | prompt 34 | MinimumRecommendedRules.ruleset 35 | 36 | 37 | 38 | ..\Dependencies\Microsoft.Cci.ILGenerator.dll 39 | 40 | 41 | ..\Dependencies\Microsoft.Cci.MetadataHelper.dll 42 | 43 | 44 | ..\Dependencies\Microsoft.Cci.MetadataModel.dll 45 | 46 | 47 | ..\Dependencies\Microsoft.Cci.MutableMetadataModel.dll 48 | 49 | 50 | ..\Dependencies\Microsoft.Cci.PdbReader.dll 51 | 52 | 53 | ..\Dependencies\Microsoft.Cci.PdbWriter.dll 54 | 55 | 56 | ..\Dependencies\Microsoft.Cci.PeReader.dll 57 | 58 | 59 | ..\Dependencies\Microsoft.Cci.PeWriter.dll 60 | 61 | 62 | ..\Dependencies\Microsoft.Cci.SourceModel.dll 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | {45C7B613-E32D-43E8-8030-932D509602EB} 81 | Backend 82 | 83 | 84 | 85 | 92 | -------------------------------------------------------------------------------- /Console/MethodVisitor.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Edgardo Zoppi. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. 2 | 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using Microsoft.Cci.MutableCodeModel; 8 | using Microsoft.Cci; 9 | using Backend; 10 | using Backend.Analysis; 11 | using Backend.Serialization; 12 | using Backend.ThreeAddressCode; 13 | 14 | namespace Console 15 | { 16 | class MethodVisitor : MetadataRewriter 17 | { 18 | private ISourceLocationProvider sourceLocationProvider; 19 | 20 | public MethodVisitor(IMetadataHost host, ISourceLocationProvider sourceLocationProvider) 21 | : base(host) 22 | { 23 | this.sourceLocationProvider = sourceLocationProvider; 24 | } 25 | 26 | public override IMethodDefinition Rewrite(IMethodDefinition methodDefinition) 27 | { 28 | var signature = MemberHelper.GetMethodSignature(methodDefinition, NameFormattingOptions.Signature | NameFormattingOptions.ParameterName); 29 | System.Console.WriteLine(signature); 30 | 31 | var disassembler = new Disassembler(host, methodDefinition, sourceLocationProvider); 32 | var methodBody = disassembler.Execute(); 33 | 34 | //System.Console.WriteLine(methodBody); 35 | //System.Console.WriteLine(); 36 | 37 | var cfg = ControlFlowGraph.GenerateNormalControlFlow(methodBody); 38 | ControlFlowGraph.ComputeDominators(cfg); 39 | ControlFlowGraph.IdentifyLoops(cfg); 40 | 41 | ControlFlowGraph.ComputeDominatorTree(cfg); 42 | ControlFlowGraph.ComputeDominanceFrontiers(cfg); 43 | 44 | var splitter = new WebAnalysis(cfg); 45 | splitter.Analyze(); 46 | splitter.Transform(); 47 | 48 | methodBody.UpdateVariables(); 49 | 50 | var typeAnalysis = new TypeInferenceAnalysis(cfg); 51 | typeAnalysis.Analyze(); 52 | 53 | var forwardCopyAnalysis = new ForwardCopyPropagationAnalysis(cfg); 54 | forwardCopyAnalysis.Analyze(); 55 | forwardCopyAnalysis.Transform(methodBody); 56 | 57 | var backwardCopyAnalysis = new BackwardCopyPropagationAnalysis(cfg); 58 | backwardCopyAnalysis.Analyze(); 59 | backwardCopyAnalysis.Transform(methodBody); 60 | 61 | //var pointsTo = new PointsToAnalysis(cfg); 62 | //var result = pointsTo.Analyze(); 63 | 64 | var ssa = new StaticSingleAssignmentAnalysis(methodBody, cfg); 65 | ssa.Transform(); 66 | 67 | methodBody.UpdateVariables(); 68 | 69 | ////var dot = DOTSerializer.Serialize(cfg); 70 | var dgml = DGMLSerializer.Serialize(cfg); 71 | 72 | return base.Rewrite(methodDefinition); 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /Console/Program.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Edgardo Zoppi. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. 2 | 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using Microsoft.Cci; 8 | using Backend; 9 | 10 | namespace Console 11 | { 12 | class Program 13 | { 14 | static void Main(string[] args) 15 | { 16 | const string root = @"..\..\.."; 17 | //const string root = @"C:"; // casa 18 | //const string root = @"C:\Users\Edgar\Projects"; // facu 19 | 20 | const string input = root + @"\Test\bin\Debug\Test.dll"; 21 | 22 | using (var host = new PeReader.DefaultHost()) 23 | using (var assembly = new Assembly(host)) 24 | { 25 | assembly.Load(input); 26 | 27 | Types.Initialize(host); 28 | 29 | //var extractor = new TypesExtractor(host); 30 | //extractor.Extract(assembly.Module); 31 | 32 | var visitor = new MethodVisitor(host, assembly.PdbReader); 33 | visitor.Rewrite(assembly.Module); 34 | } 35 | 36 | System.Console.WriteLine("Done!"); 37 | System.Console.ReadKey(); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Console/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Edgardo Zoppi. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. 2 | 3 | using System.Reflection; 4 | using System.Runtime.CompilerServices; 5 | using System.Runtime.InteropServices; 6 | 7 | // General Information about an assembly is controlled through the following 8 | // set of attributes. Change these attribute values to modify the information 9 | // associated with an assembly. 10 | [assembly: AssemblyTitle("Console")] 11 | [assembly: AssemblyDescription("")] 12 | [assembly: AssemblyConfiguration("")] 13 | [assembly: AssemblyCompany("")] 14 | [assembly: AssemblyProduct("Console")] 15 | [assembly: AssemblyCopyright("Copyright © Edgardo Zoppi")] 16 | [assembly: AssemblyTrademark("")] 17 | [assembly: AssemblyCulture("")] 18 | 19 | // Setting ComVisible to false makes the types in this assembly not visible 20 | // to COM components. If you need to access a type in this assembly from 21 | // COM, set the ComVisible attribute to true on that type. 22 | [assembly: ComVisible(false)] 23 | 24 | // The following GUID is for the ID of the typelib if this project is exposed to COM 25 | [assembly: Guid("5699fcbc-dcec-4127-9c60-8938e66cfef8")] 26 | 27 | // Version information for an assembly consists of the following four values: 28 | // 29 | // Major Version 30 | // Minor Version 31 | // Build Number 32 | // Revision 33 | // 34 | // You can specify all the values or you can default the Build and Revision Numbers 35 | // by using the '*' as shown below: 36 | // [assembly: AssemblyVersion("1.0.*")] 37 | [assembly: AssemblyVersion("1.0.0.0")] 38 | [assembly: AssemblyFileVersion("1.0.0.0")] 39 | -------------------------------------------------------------------------------- /Dependencies/Microsoft.Cci.ILGenerator.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edgardozoppi/analysis-net/733d45a54ae6b1b77e1ac091e56e7560c97ad639/Dependencies/Microsoft.Cci.ILGenerator.dll -------------------------------------------------------------------------------- /Dependencies/Microsoft.Cci.MetadataHelper.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edgardozoppi/analysis-net/733d45a54ae6b1b77e1ac091e56e7560c97ad639/Dependencies/Microsoft.Cci.MetadataHelper.dll -------------------------------------------------------------------------------- /Dependencies/Microsoft.Cci.MetadataModel.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edgardozoppi/analysis-net/733d45a54ae6b1b77e1ac091e56e7560c97ad639/Dependencies/Microsoft.Cci.MetadataModel.dll -------------------------------------------------------------------------------- /Dependencies/Microsoft.Cci.MutableMetadataModel.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edgardozoppi/analysis-net/733d45a54ae6b1b77e1ac091e56e7560c97ad639/Dependencies/Microsoft.Cci.MutableMetadataModel.dll -------------------------------------------------------------------------------- /Dependencies/Microsoft.Cci.PdbReader.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edgardozoppi/analysis-net/733d45a54ae6b1b77e1ac091e56e7560c97ad639/Dependencies/Microsoft.Cci.PdbReader.dll -------------------------------------------------------------------------------- /Dependencies/Microsoft.Cci.PdbWriter.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edgardozoppi/analysis-net/733d45a54ae6b1b77e1ac091e56e7560c97ad639/Dependencies/Microsoft.Cci.PdbWriter.dll -------------------------------------------------------------------------------- /Dependencies/Microsoft.Cci.PeReader.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edgardozoppi/analysis-net/733d45a54ae6b1b77e1ac091e56e7560c97ad639/Dependencies/Microsoft.Cci.PeReader.dll -------------------------------------------------------------------------------- /Dependencies/Microsoft.Cci.PeWriter.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edgardozoppi/analysis-net/733d45a54ae6b1b77e1ac091e56e7560c97ad639/Dependencies/Microsoft.Cci.PeWriter.dll -------------------------------------------------------------------------------- /Dependencies/Microsoft.Cci.SourceModel.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edgardozoppi/analysis-net/733d45a54ae6b1b77e1ac091e56e7560c97ad639/Dependencies/Microsoft.Cci.SourceModel.dll -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) Edgardo Zoppi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Analysis.NET # 2 | 3 | Static analysis framework for .NET programs. 4 | 5 | Features: 6 | 7 | * Bytecode level 8 | * No need for source code 9 | * Can analyze standard libraries 10 | + Intermediate representations 11 | * Simplified bytecode 12 | * Three address code 13 | * Static single assignment 14 | * Aggregated expressions 15 | + Control-flow analysis 16 | * Normal 17 | * Exceptional 18 | * Dominance 19 | * Dominance frontier 20 | * Natural loops 21 | + Data-flow analysis 22 | * Reaching definitions 23 | * Def-use and use-def chains 24 | * Live variables 25 | * Copy propagation 26 | * Points-to 27 | + Call-graph analysis 28 | * Class hierarchy 29 | + Transformations 30 | * Webs 31 | * Inlining 32 | * Type inference 33 | + Serialization 34 | * DOT 35 | * DGML 36 | -------------------------------------------------------------------------------- /Test/Examples.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Edgardo Zoppi. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. 2 | 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | 8 | namespace Test 9 | { 10 | struct Point 11 | { 12 | public int x, y; 13 | 14 | public void ExampleShortCircuitCondition() 15 | { 16 | if (x != 0 && y != 0) 17 | { 18 | x = y; 19 | } 20 | } 21 | 22 | public Point(int a, int b) 23 | { 24 | x = a; 25 | y = b; 26 | } 27 | } 28 | 29 | public class Examples 30 | { 31 | public int F1; 32 | private static int F2 = 0; 33 | 34 | public void ExampleComplexTryCatch(int a, int b) 35 | { 36 | b = 1; 37 | 38 | while (a < 5) 39 | { 40 | try 41 | { 42 | b = 2; 43 | if (a == 1) break; 44 | b = 3; 45 | } 46 | catch 47 | { 48 | b = 4; 49 | if (a == 2) continue; 50 | b = 5; 51 | } 52 | 53 | a++; 54 | } 55 | 56 | b = 6; 57 | } 58 | 59 | public void ExampleSwitch(PlatformID x) 60 | { 61 | switch (x) 62 | { 63 | case PlatformID.Unix: 64 | this.F1 = 3; 65 | break; 66 | 67 | case PlatformID.Xbox: 68 | this.F1 = 4; 69 | break; 70 | 71 | default: 72 | this.F1 = 1000; 73 | break; 74 | } 75 | } 76 | 77 | public Type ExampleLoadToken() 78 | { 79 | var type = typeof(PlatformID); 80 | return type; 81 | } 82 | 83 | public void ExampleTryCatch() 84 | { 85 | var a = 0; 86 | 87 | try 88 | { 89 | a = 1; 90 | } 91 | catch (NotImplementedException ex1) 92 | { 93 | a = 2; 94 | } 95 | catch (NullReferenceException ex2) 96 | { 97 | a = 3; 98 | } 99 | 100 | a = 5; 101 | } 102 | 103 | public void ExampleTryFinally() 104 | { 105 | var a = 0; 106 | 107 | try 108 | { 109 | a = 1; 110 | } 111 | finally 112 | { 113 | a = 4; 114 | } 115 | 116 | a = 5; 117 | } 118 | 119 | public void ExampleTryCatchFinally() 120 | { 121 | var a = 0; 122 | 123 | try 124 | { 125 | a = 1; 126 | } 127 | catch (NotImplementedException ex1) 128 | { 129 | a = 2; 130 | } 131 | catch (NullReferenceException ex2) 132 | { 133 | a = 3; 134 | } 135 | finally 136 | { 137 | a = 4; 138 | } 139 | 140 | a = 5; 141 | } 142 | 143 | public void ExampleNestedTryCatchFinally() 144 | { 145 | var a = 0; 146 | 147 | try 148 | { 149 | a = 1; 150 | 151 | try 152 | { 153 | a = 2; 154 | } 155 | catch (NotImplementedException ex1) 156 | { 157 | a = 3; 158 | } 159 | catch (NullReferenceException ex2) 160 | { 161 | a = 4; 162 | } 163 | 164 | a = 5; 165 | } 166 | finally 167 | { 168 | a = 6; 169 | } 170 | 171 | a = 7; 172 | } 173 | 174 | public void ExampleIf() 175 | { 176 | var a = 0; 177 | 178 | if (a > 0) 179 | { 180 | a = 1; 181 | } 182 | else 183 | { 184 | a = 2; 185 | } 186 | 187 | a++; 188 | } 189 | 190 | public int Example1(int arg1) 191 | { 192 | int a = 1; 193 | int b = 2; 194 | byte c = (byte)((a + a) + (a + a) + b * arg1); 195 | 196 | if (c > 3) c = 4; 197 | else c = 5; 198 | 199 | var r = this.Plus(a, b); 200 | return r; 201 | } 202 | 203 | public int Plus(int a, int b) 204 | { 205 | //this.Print(a, b); 206 | 207 | var p1 = new Point(a, b); 208 | var p2 = p1; 209 | 210 | //var arr = new int[a, 3, 4]; 211 | //var arr2 = new int[2][][]; 212 | 213 | var obj = new Examples(); 214 | obj.F1 = 6 * obj.F1 + Examples.F2; 215 | 216 | var array = new int[3]; 217 | var tamanio = array.Length; 218 | 219 | array[a] = b; 220 | a = array[b]; 221 | 222 | return a + b; 223 | } 224 | 225 | public T Example2() 226 | { 227 | var a = default(T); 228 | return a; 229 | } 230 | 231 | //public void Print(params object[] args) 232 | //{ 233 | // Console.WriteLine(args); 234 | //} 235 | } 236 | } 237 | -------------------------------------------------------------------------------- /Test/ExamplesPointsTo.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Edgardo Zoppi. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. 2 | 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | 8 | namespace Test 9 | { 10 | class Node 11 | { 12 | public object Value; 13 | public Node Next; 14 | 15 | public Node(object value) 16 | { 17 | this.Value = value; 18 | } 19 | } 20 | 21 | class ExamplesPointsTo 22 | { 23 | public void Example1() 24 | { 25 | var node = new Node(1); 26 | node.Next = new Node(2); 27 | 28 | var first = node; 29 | var second = first.Next; 30 | var third = second.Next; 31 | third.Next = null; 32 | } 33 | 34 | public void Example2(bool a, bool b) 35 | { 36 | var node = new Node(1); 37 | 38 | if (a) node.Next = new Node(2); 39 | else if (b) node.Next = new Node(3); 40 | else node.Next = node; 41 | } 42 | 43 | public void Example3() 44 | { 45 | var current = new Node(1); 46 | 47 | for (var i = 0; i < 5; ++i) 48 | { 49 | current.Next = new Node(i + 1); 50 | current = current.Next; 51 | } 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Test/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Edgardo Zoppi. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. 2 | 3 | using System.Reflection; 4 | using System.Runtime.CompilerServices; 5 | using System.Runtime.InteropServices; 6 | 7 | // General Information about an assembly is controlled through the following 8 | // set of attributes. Change these attribute values to modify the information 9 | // associated with an assembly. 10 | [assembly: AssemblyTitle("Test")] 11 | [assembly: AssemblyDescription("")] 12 | [assembly: AssemblyConfiguration("")] 13 | [assembly: AssemblyCompany("")] 14 | [assembly: AssemblyProduct("Test")] 15 | [assembly: AssemblyCopyright("Copyright © Edgardo Zoppi")] 16 | [assembly: AssemblyTrademark("")] 17 | [assembly: AssemblyCulture("")] 18 | 19 | // Setting ComVisible to false makes the types in this assembly not visible 20 | // to COM components. If you need to access a type in this assembly from 21 | // COM, set the ComVisible attribute to true on that type. 22 | [assembly: ComVisible(false)] 23 | 24 | // The following GUID is for the ID of the typelib if this project is exposed to COM 25 | [assembly: Guid("559f1784-2196-4afa-8cf9-e06d7fd8d2de")] 26 | 27 | // Version information for an assembly consists of the following four values: 28 | // 29 | // Major Version 30 | // Minor Version 31 | // Build Number 32 | // Revision 33 | // 34 | // You can specify all the values or you can default the Build and Revision Numbers 35 | // by using the '*' as shown below: 36 | // [assembly: AssemblyVersion("1.0.*")] 37 | [assembly: AssemblyVersion("1.0.0.0")] 38 | [assembly: AssemblyFileVersion("1.0.0.0")] 39 | -------------------------------------------------------------------------------- /Test/Test.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | 8.0.30703 7 | 2.0 8 | {A7EFFB71-0EE7-413C-85C8-5C74C8D4CDB0} 9 | Library 10 | Properties 11 | Test 12 | Test 13 | v4.0 14 | 512 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | pdbonly 27 | true 28 | bin\Release\ 29 | TRACE 30 | prompt 31 | 4 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 55 | -------------------------------------------------------------------------------- /grammar_tac.txt: -------------------------------------------------------------------------------- 1 | Three Address Code Grammar 2 | -------------------------- 3 | 4 | instruction ::= copy | load_access | store_access | load_method | unary | binary | call | branch | return . 5 | 6 | branch ::= unconditional | conditional . 7 | 8 | unconditional ::= "goto" LABEL . 9 | conditional ::= "if" variable "goto" LABEL . 10 | 11 | return ::= "return" [variable] . 12 | 13 | copy ::= variable "=" operand . 14 | load_access ::= variable "=" access . 15 | store_access ::= access "=" variable . 16 | 17 | load_method ::= variable "=" "&" TYPE "::" METHOD "(" [variable] ")" . 18 | 19 | unary ::= variable "=" unary_op variable . 20 | binary ::= variable "=" variable binary_op variable . 21 | 22 | call ::= [variable "="] TYPE "::" METHOD "(" variable "," ... "," variable ")" . 23 | 24 | access ::= static_field | instance_field | array_element | indirect . 25 | 26 | static_field ::= TYPE "::" IDENTIFIER . 27 | instance_field ::= variable "." IDENTIFIER . 28 | array_element ::= variable "[" variable "]" . 29 | indirect ::= "*" variable . 30 | 31 | operand ::= variable | constant . 32 | variable ::= local | temporal | derived . 33 | 34 | derived ::= local_i . 35 | temporal ::= "t_i" . 36 | local ::= IDENTIFIER . 37 | constant ::= LITERAL . 38 | 39 | unary_op ::= "!" | "&" . 40 | binary_op ::= "+" | "-" | ... . 41 | -------------------------------------------------------------------------------- /instructions.txt: -------------------------------------------------------------------------------- 1 | CIL Instruction Set 2 | 3 | > Arithmetic instructions 4 | 5 | >> Binary arithmetic instructions 6 | 7 | add // add numeric values 8 | add.ovf. // add integer values with overflow check 9 | 10 | sub // subtract numeric values 11 | sub.ovf. // subtract integer values with overflow check 12 | 13 | mul // multiply numeric values 14 | mul.ovf. // multiply integer values with overflow check 15 | 16 | div // divide numeric values 17 | div.un // divide integer values, unsigned 18 | 19 | rem // compute numeric remainder 20 | rem.un // compute integer remainder, unsigned 21 | 22 | and // bitwise AND 23 | or // bitwise OR 24 | xor // bitwise XOR 25 | 26 | shl // shift integer left 27 | shr // shift integer right 28 | shr.un // shift integer right, unsigned 29 | 30 | >> Unary arithmetic instructions 31 | 32 | neg // negate 33 | not // bitwise complement 34 | 35 | > Branch instructions 36 | 37 | >> Conditional branch instructions 38 | 39 | beq. // branch on equal 40 | bge. // branch on greater than or equal to 41 | bge.un. // branch on greater than or equal to, unsigned or unordered 42 | bgt. // branch on greater than 43 | bgt.un. // branch on greater than, unsigned or unordered 44 | ble. // branch on less than or equal to 45 | ble.un. // branch on less than or equal to, unsigned or unordered 46 | blt. // branch on less than 47 | blt.un. // branch on less than, unsigned or unordered 48 | bne.un // branch on not equal or unordered 49 | brfalse. // branch on false, null, or zero 50 | brtrue. // branch on non-false or non-null 51 | 52 | switch // table switch based on value 53 | 54 | >> Unconditional branch instructions 55 | 56 | br. // unconditional branch 57 | leave. // exit a protected region of code 58 | ret // return from method 59 | 60 | > Call instructions 61 | 62 | call // call a method 63 | callvirt // call a method associated, at runtime, with an object 64 | calli // indirect method call 65 | jmp // jump to method 66 | 67 | > Compare instructions 68 | 69 | ceq // compare equal 70 | cgt // compare greater than 71 | cgt.un // compare greater than, unsigned or unordered 72 | clt // compare less than 73 | clt.un // compare less than, unsigned or unordered 74 | 75 | isinst // test if an object is an instance of a class or interface 76 | 77 | > Convert instructions 78 | 79 | conv. // data conversion 80 | conv.ovf. // data conversion with overflow check 81 | conv.ovf..un // data conversion with overflow check, unsigned 82 | 83 | box // convert a boxable value to its boxed form 84 | castclass // cast an object to a class 85 | 86 | unbox // convert boxed value type to its raw form 87 | unbox.any // convert boxed type to value 88 | 89 | > Memory instructions 90 | 91 | localloc // allocate space in the local dynamic memory pool 92 | initblk // initialize a block of memory to a value 93 | cpblk // copy data from memory to memory 94 | 95 | cpobj // copy a value from one address to another 96 | initobj // initialize the value at an address 97 | 98 | newarr // create a zero-based, one-dimensional array 99 | newobj // create a new object 100 | 101 | > Exception handling instructions 102 | 103 | endfilter // end exception handling filter clause 104 | endfinally // end finally or fault clause of an exception block 105 | 106 | throw // throw an exception 107 | rethrow // rethrow the current exception 108 | 109 | > Load instructions 110 | 111 | ldc. // load numeric constant 112 | ldstr // load a literal string 113 | ldnull // load a null pointer 114 | 115 | ldarg. // load argument onto the stack 116 | ldloc // load local variable onto the stack 117 | 118 | ldind. // load a value indirect onto the stack 119 | ldobj // copy a value from an address to the stack 120 | 121 | ldarga. // load argument address 122 | ldloca. // load local variable address 123 | 124 | ldftn // load method pointer 125 | ldvirtftn // load virtual method pointer 126 | 127 | ldelem // load array element 128 | ldelem. // load array element 129 | ldelema // load array element address 130 | 131 | ldfld // load object field 132 | ldflda // load object field address 133 | 134 | ldsfld // load class static field 135 | ldsflda // load class static field address 136 | 137 | ldlen // load array length 138 | 139 | ldtoken // load the runtime representation of a metadata token 140 | 141 | > Store instructions 142 | 143 | starg. // store to argument 144 | stloc // store to local variable 145 | 146 | stind. // store a value indirect from stack 147 | stobj // store a value at an address from stack 148 | 149 | stelem // store array element 150 | stelem. // store array element 151 | 152 | stfld // store object field 153 | stsfld // store class static field 154 | 155 | > Other instructions 156 | 157 | arglist // get argument list 158 | 159 | break // breakpoint instruction 160 | 161 | ckfinite // check for a finite real number 162 | 163 | nop // no operation 164 | dup // duplicate the top value of the stack 165 | pop // remove the top element of the stack 166 | 167 | mkrefany // push a typed reference on the stack 168 | refanytype // load the type out of a typed reference 169 | refanyval // load the address out of a typed reference 170 | 171 | sizeof // load the size, in bytes, of a type 172 | --------------------------------------------------------------------------------