예제 #1
0
        /// <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();
                }
            }
        }
예제 #2
0
        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();
        }
예제 #3
0
        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);
            }
        }
예제 #4
0
        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);
        }
예제 #5
0
        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();
        }
예제 #6
0
        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);
                }
            }
        }
예제 #7
0
    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;
    }
예제 #8
0
 /// <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());
 }