IKVM.Internal.CodeEmitter.MergeExceptionBlocks C# (CSharp) Method

MergeExceptionBlocks() private method

private MergeExceptionBlocks ( ) : void
return void
        private void MergeExceptionBlocks()
        {
            // The first loop will convert all Begin[Exception|Catch|Fault|Finally]Block and EndExceptionBlock
            // pseudo opcodes into a cyclic linked list (EndExceptionBlock links back to BeginExceptionBlock)
            // to allow for easy traversal in the next loop.
            int[] extra = new int[code.Count];
            Stack<int> stack = new Stack<int>();
            int currentBeginExceptionBlock = -1;
            int currentLast = -1;
            for (int i = 0; i < code.Count; i++)
            {
                switch (code[i].pseudo)
                {
                    case CodeType.BeginExceptionBlock:
                        stack.Push(currentBeginExceptionBlock);
                        currentBeginExceptionBlock = i;
                        currentLast = i;
                        break;
                    case CodeType.EndExceptionBlock:
                        extra[currentLast] = i;
                        extra[i] = currentBeginExceptionBlock;
                        currentBeginExceptionBlock = stack.Pop();
                        currentLast = currentBeginExceptionBlock;
                        if (currentLast != -1)
                        {
                            while (extra[currentLast] != 0)
                            {
                                currentLast = extra[currentLast];
                            }
                        }
                        break;
                    case CodeType.BeginCatchBlock:
                    case CodeType.BeginFaultBlock:
                    case CodeType.BeginFinallyBlock:
                        extra[currentLast] = i;
                        currentLast = i;
                        break;
                }
            }

            // Now we look for consecutive exception blocks that have the same fault handler
            for (int i = 0; i < code.Count - 1; i++)
            {
                if (code[i].pseudo == CodeType.EndExceptionBlock
                    && code[i + 1].pseudo == CodeType.BeginExceptionBlock)
                {
                    if (IsFaultOnlyBlock(extra, extra[i]) && IsFaultOnlyBlock(extra, i + 1))
                    {
                        int beginFault1 = extra[extra[i]];
                        int beginFault2 = extra[i + 1];
                        int length1 = extra[beginFault1] - beginFault1;
                        int length2 = extra[beginFault2] - beginFault2;
                        if (length1 == length2 && MatchHandlers(beginFault1, beginFault2, length1))
                        {
                            // Check if the labels at the start of the handler are reachable from outside
                            // of the new combined block.
                            for (int j = i + 2; j < beginFault2; j++)
                            {
                                if (code[j].pseudo == CodeType.OpCode)
                                {
                                    break;
                                }
                                else if (code[j].pseudo == CodeType.Label)
                                {
                                    if (HasBranchTo(0, extra[i], code[j].Label)
                                        || HasBranchTo(beginFault2 + length2, code.Count, code[j].Label))
                                    {
                                        goto no_merge;
                                    }
                                }
                            }
                            // Merge the two blocks by overwritting the first fault block and
                            // the BeginExceptionBlock of the second block.
                            for (int j = beginFault1; j < i + 2; j++)
                            {
                                code[j] = new OpCodeWrapper(OpCodes.Nop, null);
                            }
                            // Repair the linking structure.
                            extra[extra[i]] = beginFault2;
                            extra[extra[beginFault2]] = extra[i];
                        }
                    }
                no_merge: ;
                }
            }
        }