コード例 #1
0
ファイル: Instructions.cs プロジェクト: dbremner/perwapi
        /// <summary>
        /// Returns the maximum stack depth required by these CIL instructions.
        /// </summary>
        /// <returns>The integer value of the stck depth.</returns>
        public int GetMaxStackDepthRequired()
        {
            if (tide == 0) return 0;

              // Store the code blocks we find
              SCG.List<CodeBlock> codeBlocks = new SCG.List<CodeBlock>();
              SCG.Dictionary<CILLabel, CodeBlock> cbTable = new SCG.Dictionary<CILLabel, CodeBlock>();
              SCG.List<CodeBlock> extraStartingBlocks = new SCG.List<CodeBlock>();

              // Start a default code block
              CodeBlock codeBlock = new CodeBlock(this);
              codeBlock.StartIndex = 0;

              //
              // Identify the code blocks
              //
              for (int i = 0; i < tide; i++) {

            /* Handling the tail instruction:
             * The tail instruction has not been handled even though
             * it indicates the end of a code block is coming.  The
             * reason for this is because any valid tail instruction
             * must be followed by a call* instruction and then a ret
             * instruction.  Given a ret instruction must be the second
             * next instruction anyway it has been decided to just let
             * the end block be caught then.
             */

            // If we reach a branch instruction or a switch instruction
            // then end the current code block inclusive of the instruction.
            if ((buffer[i] is BranchInstr) || (buffer[i] is SwitchInstr)) {

              // Close the old block
              codeBlock.EndIndex = i;
              if (codeBlock.EndIndex >= codeBlock.StartIndex) // Don't add empty blocks
            codeBlocks.Add(codeBlock);

              // Open a new block
              codeBlock = new CodeBlock(this);
              codeBlock.StartIndex = i + 1;

              // If we reach a label then we need to start a new
              // code block as the label is an entry point.
            }
            else if (buffer[i] is CILLabel) {

              // Close the old block
              codeBlock.EndIndex = i - 1;
              if (codeBlock.EndIndex >= codeBlock.StartIndex) // Don't add empty blocks
            codeBlocks.Add(codeBlock);

              // Open a new block
              codeBlock = new CodeBlock(this);
              codeBlock.StartIndex = i;

              // Set this label as the entry point for the code block
              codeBlock.EntryLabel = (CILLabel)buffer[i];
              // AND ... list in the dictionary.
              cbTable.Add(codeBlock.EntryLabel, codeBlock);

              // Check for the ret, throw, rethrow, or jmp instruction as they also end a block
            }
            else if (buffer[i] is Instr) {
              if (
              (((Instr)buffer[i]).GetOp() == Op.ret) ||
              (((Instr)buffer[i]).GetOp() == Op.throwOp) ||
              (((Instr)buffer[i]).GetOp() == Op.rethrow) ||
              ((buffer[i] is MethInstr) && (((MethInstr)buffer[i]).GetMethodOp() == MethodOp.jmp))
             ) {

            // Close the old block
            codeBlock.EndIndex = i;
            if (codeBlock.EndIndex >= codeBlock.StartIndex) // Don't add empty blocks
              codeBlocks.Add(codeBlock);

            // Open a new block
            // In theory this should never happen but just in case
            // someone feels like adding dead code it is supported.
            codeBlock = new CodeBlock(this);
            codeBlock.StartIndex = i + 1;

              }

            }

              }

              // Close the last block
              codeBlock.EndIndex = tide - 1;
              if (codeBlock.EndIndex >= codeBlock.StartIndex) // Don't add empty blocks
            codeBlocks.Add(codeBlock);
              codeBlock = null;

              // Check how many code blocks there are.  If an blocks return 0.
              if (codeBlocks.Count == 0) return 0;

              //
              // Loop through each code block and calculate the delta distance
              //
              for (int j = 0; j < codeBlocks.Count; j++) {
            CodeBlock block = codeBlocks[j];

            int maxDepth = 0;
            int currentDepth = 0;

            // Loop through each instruction to work out the max depth
            for (int i = block.StartIndex; i <= block.EndIndex; i++) {

              // Get the depth after the next instruction
              currentDepth += buffer[i].GetDeltaDistance();

              // If the new current depth is greater then the maxDepth adjust the maxDepth to reflect
              if (currentDepth > maxDepth)
            maxDepth = currentDepth;

            }

            // Set the depth of the block
            block.MaxDepth = maxDepth;
            block.DeltaDistance = currentDepth;

            //
            // Link up the next blocks
            //

            // If the block ends with a branch statement set the jump and fall through.
            if (buffer[block.EndIndex] is BranchInstr) {
              BranchInstr branchInst = (BranchInstr)buffer[block.EndIndex];

              // If this is not a "br" or "br.s" then set the fall through code block
              if ((branchInst.GetBranchOp() != BranchOp.br) &&
              (branchInst.GetBranchOp() != BranchOp.br_s))
            // If there is a following code block set it as the fall through
            if (j < (codeBlocks.Count - 1))
              block.NextBlocks.Add(codeBlocks[j + 1]);

              // Set the code block we are jumping to
              CodeBlock cb;
              cbTable.TryGetValue(branchInst.GetDest(), out cb);
              if (cb == null)
            throw new Exception("Missing Branch Label");
              block.NextBlocks.Add(cb);

              // If the block ends in a switch instruction work out the possible next blocks
            }
            else if (buffer[block.EndIndex] is SwitchInstr) {
              SwitchInstr switchInstr = (SwitchInstr)buffer[block.EndIndex];

              // If there is a following code block set it as the fall through
              if (j < (codeBlocks.Count - 1))
            block.NextBlocks.Add(codeBlocks[j + 1]);

              // Add each destination block
              foreach (CILLabel label in switchInstr.GetDests()) {

            // Check all of the code blocks to find the jump destination
            CodeBlock cb;
            cbTable.TryGetValue(label, out cb);
            if (cb == null) throw new Exception("Missing Case Label");
            block.NextBlocks.Add(cb);

              }

              // So long as the block doesn't end with a terminating instruction like ret or throw, just fall through to the next block
            }
            else if (!IsTerminatingInstruction(buffer[block.EndIndex])) {

              // If there is a following code block set it as the fall through
              if (j < (codeBlocks.Count - 1))
            block.NextBlocks.Add(codeBlocks[j + 1]);
            }

              }

              //
              // Join up any exception blocks
              //

              if (exceptions != null) {
            foreach (TryBlock tryBlock in exceptions) {

              // Try to find the code block where this try block starts
              CodeBlock tryCodeBlock;
              cbTable.TryGetValue(tryBlock.Start, out tryCodeBlock);

              // Declare that the entry to this code block must be empty
              tryCodeBlock.RequireEmptyEntry = true;

              // Work with each of the handlers
              foreach (HandlerBlock hb in tryBlock.GetHandlers()) {

            // Find the code block where this handler block starts.
            CodeBlock handlerCodeBlock;
            cbTable.TryGetValue(hb.Start, out handlerCodeBlock);

            // If the code block is a catch or filter block increment the delta
            // distance by 1. This is to factor in the exception object that will
            // be secretly placed on the stack by the runtime engine.
            // However, this also means that the MaxDepth is up by one also!
            if (hb is Catch || hb is Filter) {
              handlerCodeBlock.DeltaDistance++;
              handlerCodeBlock.MaxDepth++;
            }

            // If the code block is a filter block increment the delta distance by 1
            // This is to factor in the exception object that will be placed on the stack.
            // if (hb is Filter) handlerCodeBlock.DeltaDistance++;

            // Add this handler to the list of starting places
            extraStartingBlocks.Add(handlerCodeBlock);

              }

            }
              }

              //
              // Traverse the code blocks and get the depth
              //

              // Get the max depth at the starting entry point
              int finalMaxDepth = TraverseMaxDepth(codeBlocks[0]);

              // Check the additional entry points
              // If the additional points have a greater depth update the max depth
              foreach (CodeBlock cb in extraStartingBlocks) {
            // int tmpMaxDepth = cb.TraverseMaxDepth();
            int tmpMaxDepth = TraverseMaxDepth(cb);
            if (tmpMaxDepth > finalMaxDepth) finalMaxDepth = tmpMaxDepth;
              }

              // Return the max depth we have found
              return finalMaxDepth;
        }
コード例 #2
0
ファイル: Instructions.cs プロジェクト: dbremner/perwapi
        private static int TraverseMaxDepth(CodeBlock entryBlock)
        {
            int max = 0;
              SCG.Queue<CodeBlock> worklist = new SCG.Queue<CodeBlock>();
              entryBlock.Visited = true;
              entryBlock.LastVisitEntryDepth = 0;
              worklist.Enqueue(entryBlock);
              while (worklist.Count > 0) {
            int count = worklist.Count;
            CodeBlock unit = worklist.Dequeue();

            int maxDepth = unit.LastVisitEntryDepth + unit.MaxDepth;
            int exitDepth = unit.LastVisitEntryDepth + unit.DeltaDistance;

            if (maxDepth > max) max = maxDepth;

            foreach (CodeBlock succ in unit.NextBlocks) {
              if (succ.Visited) {
            if (succ.LastVisitEntryDepth != exitDepth)
              throw new InvalidStackDepth("inconsistent stack depth at offset " + succ.StartIndex.ToString());
              }
              else {
            succ.Visited = true;
            succ.LastVisitEntryDepth = exitDepth;
            worklist.Enqueue(succ);
              }
            }
              }
              return max;
        }