/// <summary> /// /// </summary> internal static void FillInTypes(IMetadataHost host, ControlAndDataFlowGraph <BasicBlock, Instruction> cfg) { Contract.Requires(host != null); Contract.Requires(cfg != null); var stack = new Stack <Instruction>(cfg.MethodBody.MaxStack, new List <Instruction>(0)); var numberOfBlocks = cfg.BlockFor.Count; var blocksToVisit = new Queue <BasicBlock>((int)numberOfBlocks); var blocksAlreadyVisited = new SetOfObjects(numberOfBlocks); var inferencer = new TypeInferencer <BasicBlock, Instruction>(host, cfg, stack, blocksToVisit, blocksAlreadyVisited); foreach (var root in cfg.RootBlocks) { blocksToVisit.Enqueue(root); while (blocksToVisit.Count != 0) { inferencer.DequeueBlockAndFillInItsTypes(); } } //At this point, all reachable code blocks have had their types inferred. Now look for unreachable blocks. foreach (var block in cfg.AllBlocks) { if (blocksAlreadyVisited.Contains(block)) { continue; } blocksToVisit.Enqueue(block); while (blocksToVisit.Count != 0) { inferencer.DequeueBlockAndFillInItsTypes(); } } }
private void DequeueBlockAndFillInItsTypes() { var block = this.blocksToVisit.Dequeue(); Contract.Assume(block != null); //this.blocksToVisit only has non null elements, but we can't put that in a contract that satisfies the checker if (!this.blocksAlreadyVisited.Add(block)) { return; //The same block can be added multiple times to the queue. } //The block either has no operand stack setup instructions, or we presume that a predecessor block has already assigned types to them. foreach (var stackSetupInstruction in block.OperandStack) { Contract.Assume(stackSetupInstruction != null); //block.OperandStack only has non null elements, but we can't put that in a contract that satisfies the checker this.stack.Push(stackSetupInstruction); } foreach (var instruction in block.Instructions) { Contract.Assume(instruction != null); //block.Instructions only has non null elements, but we can't put that in a contract that satisfies the checker this.InferTypeAndUpdateStack(instruction); } foreach (var successor in this.cfg.SuccessorsFor(block)) { Contract.Assume(successor != null); //block.Successors only has non null elements, but we can't put that in a contract that satisfies the checker this.TransferTypesFromStackTo(successor); if (blocksAlreadyVisited.Contains(successor)) { continue; } blocksToVisit.Enqueue(successor); //The block might already be in the queue, but we can deal with this more efficiently by checking blocksAlreadyVisited when dequeueing. } this.stack.Clear(); }
private void AddEdgesForSwitch(IOperation ilOperation, BasicBlock currentBlock, List <BasicBlock> edges, Instruction instruction) { Contract.Requires(ilOperation != null); Contract.Requires(currentBlock != null); Contract.Requires(ilOperation.OperationCode == OperationCode.Switch); Contract.Requires(edges != null); Contract.Requires(instruction != null); Contract.Assume(ilOperation.Value is uint[]); //This is an informally specified property of the Metadata model. uint[] branches = (uint[])ilOperation.Value; SetOfObjects currentSuccesors = new SetOfObjects((uint)branches.Length); foreach (uint targetAddress in branches) { this.blocksThatTarget.Add(targetAddress, currentBlock); var target = this.cdfg.BlockFor[targetAddress]; Contract.Assume(target != null); //All branch targets must have blocks, but we can't put that in a contract that satisfies the checker. if (currentSuccesors.Contains(target)) { continue; } currentSuccesors.Add(target); edges.Add(target); } }
private void SetupTraversalOrders() { Contract.Ensures(this.postOrder != null); Contract.Ensures(this.preOrder != null); var n = cfg.AllBlocks.Count; this.postOrder = new BasicBlock[n]; this.preOrder = new BasicBlock[n]; uint preorderCounter = 0; uint postorderCounter = 0; var alreadyTraversed = new SetOfObjects((uint)n); foreach (var rootBlock in cfg.RootBlocks) { Contract.Assume(rootBlock != null); this.SetupTraversalOrders(rootBlock, alreadyTraversed, ref preorderCounter, ref postorderCounter); } Contract.Assume(preorderCounter == postorderCounter); if (preorderCounter != n) { //Add unreachable blocks to traversal order, treating them as if they were roots. foreach (var block in cfg.AllBlocks) { Contract.Assume(block != null); if (alreadyTraversed.Contains(block)) { continue; } this.SetupTraversalOrders(block, alreadyTraversed, ref preorderCounter, ref postorderCounter); } } Contract.Assume(this.postOrder != null); Contract.Assume(this.preOrder != null); }
private void DequeueBlockAndSetupDataFlow() { var block = this.blocksToVisit.Dequeue(); Contract.Assume(block != null); //this.blocksToVisit only has non null elements, but we can't put that in a contract that satisfies the checker if (!this.blocksAlreadyVisited.Add(block)) { return; //The same block can be added multiple times to the queue. } foreach (var instruction in block.OperandStack) { Contract.Assume(instruction != null); //block.OperandStack only has non null elements, but we can't put that in a contract that satisfies the checker this.stack.Push(instruction); } foreach (var instruction in block.Instructions) { Contract.Assume(instruction != null); //block.Instructions only has non null elements, but we can't put that in a contract that satisfies the checker this.SetupDataFlowFor(instruction); } foreach (var successor in this.cdfg.SuccessorsFor(block)) { Contract.Assume(successor != null); //block.Successors only has non null elements, but we can't put that in a contract that satisfies the checker this.SetupStackFor(successor); if (blocksAlreadyVisited.Contains(successor)) { continue; } blocksToVisit.Enqueue(successor); //The block might already be in the queue, but we can deal with this more efficiently by checking blocksAlreadyVisited when dequeueing. } this.stack.Clear(); }
private void AddTransferInstructions(BasicBlock block, BasicBlock succ, int successorIndex, SetOfObjects definedSSAVariables) { Contract.Requires(block != null); Contract.Requires(succ != null); Contract.Requires(definedSSAVariables != null); if (succ.Joins == null) { return; } foreach (var join in succ.Joins) { Contract.Assume(join.Join1 != null); if (definedSSAVariables.Contains(join.Join1)) { this.AddTransferInstruction(block, succ, successorIndex, join.NewLocal, join.Join1, join.Type); continue; } if (join.Join2 == null) { continue; } if (definedSSAVariables.Contains(join.Join2)) { this.AddTransferInstruction(block, succ, successorIndex, join.NewLocal, join.Join2, join.Type); continue; } if (join.OtherJoins == null) { continue; } foreach (var joini in join.OtherJoins) { if (!definedSSAVariables.Contains(joini)) { continue; } this.AddTransferInstruction(block, succ, successorIndex, join.NewLocal, joini, join.Type); } } }
private bool NextReferenceIsAssignment(ILocalDefinition local, BasicBlock<Instruction> bb, int offset, SetOfObjects blocksAlreadyVisited) { Contract.Requires(bb != null); Contract.Requires(offset >= 0); Contract.Requires(blocksAlreadyVisited != null); blocksAlreadyVisited.Add(bb); for (int i = offset, n = bb.Instructions.Count; i < n; i++) { var instruction = bb.Instructions[i]; switch (instruction.Operation.OperationCode) { case OperationCode.Ldloc: case OperationCode.Ldloc_0: case OperationCode.Ldloc_1: case OperationCode.Ldloc_2: case OperationCode.Ldloc_3: case OperationCode.Ldloc_S: case OperationCode.Ldloca: case OperationCode.Ldloca_S: if (instruction.Operation.Value == local) return false; break; case OperationCode.Stloc: case OperationCode.Stloc_0: case OperationCode.Stloc_1: case OperationCode.Stloc_2: case OperationCode.Stloc_3: case OperationCode.Stloc_S: if (instruction.Operation.Value == local) return true; break; } } var result = true; foreach (var successor in this.cdfg.SuccessorsFor(bb)) { Contract.Assume(successor != null); if (blocksAlreadyVisited.Contains(successor)) continue; result &= this.NextReferenceIsAssignment(local, successor, 0, blocksAlreadyVisited); if (!result) break; } return result; }
/// <summary> /// Provides the host with an opportunity to add, remove or substitute assembly references in the given list. /// This avoids the cost of rewriting the entire unit in order to make such changes. /// </summary> /// <param name="referringUnit">The unit that contains these references.</param> /// <param name="assemblyReferences">The assembly references to substitute.</param> /// <returns>Usually assemblyReferences, but occasionally a modified enumeration.</returns> public override IEnumerable<IAssemblyReference> Redirect(IUnit referringUnit, IEnumerable<IAssemblyReference> assemblyReferences) { if (!this.projectToCLRTypes) return assemblyReferences; var referringModule = referringUnit as IModule; if (referringModule == null || referringModule.ContainingAssembly == null || !(referringModule.ContainingAssembly.ContainsForeignTypes)) return assemblyReferences; var platformType = (WindowsRuntimePlatform)this.PlatformType; var standardRefs = new SetOfObjects(); if (string.Equals(this.CoreAssemblySymbolicIdentity.Name.Value, "System.Runtime", StringComparison.OrdinalIgnoreCase)) { standardRefs.Add(platformType.SystemObjectModel.AssemblyIdentity); } else { standardRefs.Add(platformType.System.AssemblyIdentity); } standardRefs.Add(platformType.CoreAssemblyRef.AssemblyIdentity); standardRefs.Add(platformType.SystemRuntimeWindowsRuntime.AssemblyIdentity); standardRefs.Add(platformType.SystemRuntimeWindowsRuntimeUIXaml.AssemblyIdentity); var result = new List<IAssemblyReference>(); foreach (var aref in assemblyReferences) { if (string.Equals(aref.Name.Value, "mscorlib", StringComparison.OrdinalIgnoreCase)) continue; result.Add(aref); standardRefs.Remove(aref.AssemblyIdentity); } if (standardRefs.Contains(platformType.CoreAssemblyRef.AssemblyIdentity)) result.Add(platformType.CoreAssemblyRef); if (standardRefs.Contains(platformType.SystemRuntimeInteropServicesWindowsRuntime.AssemblyIdentity)) result.Add(platformType.SystemRuntimeInteropServicesWindowsRuntime); if (standardRefs.Contains(platformType.SystemRuntimeWindowsRuntime.AssemblyIdentity)) result.Add(platformType.SystemRuntimeWindowsRuntime); if (standardRefs.Contains(platformType.SystemRuntimeWindowsRuntimeUIXaml.AssemblyIdentity)) result.Add(platformType.SystemRuntimeWindowsRuntimeUIXaml); if (standardRefs.Contains(platformType.SystemObjectModel.AssemblyIdentity)) result.Add(platformType.SystemObjectModel); if (standardRefs.Contains(platformType.System.AssemblyIdentity)) result.Add(platformType.System); return IteratorHelper.GetReadonly(result.ToArray()); }