Пример #1
0
 public override string ToString()
 {
     if (Exception != null)
     {
         return($"[{GetType ().Name}: {Target} {Exception.HandlerType}]");
     }
     return($"[{GetType ().Name}: {Target} <== {OriginBlock} - {CecilHelper.Format (Origin)}]");
 }
Пример #2
0
 internal void CheckRemoveJumpOrigin(BasicBlock block)
 {
     if (CecilHelper.IsBranch(block.BranchType))
     {
         var target = GetBlock((Instruction)block.LastInstruction.Operand);
         target.RemoveJumpOrigin(block.LastInstruction);
     }
 }
        bool RemoveConstantJumps(ref BasicBlock block, int index)
        {
            if (Scanner.DebugLevel > 2)
            {
                Scanner.LogDebug(2, $"  #{index}: {block}");
                Scanner.LogDebug(2, "  ", null, block.JumpOrigins);
                Scanner.LogDebug(2, "  ", null, block.Instructions);
                Scanner.Context.Debug();
            }

            bool constant;

            switch (block.BranchType)
            {
            case BranchType.True:
                if (block.Count < 2)
                {
                    return(false);
                }
                if (!CecilHelper.IsConstantLoad(block.Instructions [block.Count - 2], out constant))
                {
                    return(false);
                }
                break;

            case BranchType.False:
                if (block.Count < 2)
                {
                    return(false);
                }
                if (!CecilHelper.IsConstantLoad(block.Instructions [block.Count - 2], out constant))
                {
                    return(false);
                }
                constant = !constant;
                break;

            default:
                return(false);
            }

            var target = (Instruction)block.LastInstruction.Operand;

            Scanner.LogDebug(2, $"  ELIMINATE CONSTANT JUMP: {constant} {block.LastInstruction} {CecilHelper.Format (target)}");

            BlockList.RemoveInstructionAt(ref block, block.Count - 1);
            if (constant)
            {
                BlockList.ReplaceInstructionAt(ref block, block.Count - 1, Instruction.Create(OpCodes.Br, target));
            }
            else
            {
                BlockList.RemoveInstructionAt(ref block, block.Count - 1);
            }

            return(true);
        }
Пример #4
0
 void CheckAddJumpOrigin(BasicBlock block)
 {
     if (CecilHelper.IsBranch(block.BranchType))
     {
         // We are adding a new branch instruction.
         var target = _bb_by_instruction [(Instruction)block.LastInstruction.Operand];
         target.AddJumpOrigin(new JumpOrigin(target, block, block.LastInstruction));
     }
 }
Пример #5
0
        /*
         * The block @block contains a linker conditional that resolves into the
         * boolean constant @condition.  There are @stackDepth extra values on the
         * stack and the block ends with a branch instruction.
         *
         * If @condition is true, then we replace the branch with a direct jump.
         *
         * If @condition is false, then we remove the branch.
         *
         * In either case, we need to make sure to pop the extra @stackDepth values
         * off the stack.
         *
         */
        public void ReplaceWithBranch(ref BasicBlock block, int stackDepth, bool condition)
        {
            if (!CecilHelper.IsBranch(block.BranchType))
            {
                throw new OptimizerAssertionException($"{nameof (ReplaceWithBranch)} used on non-branch block.");
            }

            Instruction branch = null;

            if (condition)
            {
                branch = Instruction.Create(OpCodes.Br, (Instruction)block.LastInstruction.Operand);
            }

            ReplaceWithInstruction(ref block, stackDepth, branch);
        }
Пример #6
0
        bool Scan()
        {
            LogDebug(1, $"SCAN: {Method}");

            BasicBlock bb = null;

            if (DebugLevel > 0)
            {
                Context.Debug();
            }

            if (!BlockList.Initialize())
            {
                return(false);
            }

            for (int i = 0; i < Method.Body.Instructions.Count; i++)
            {
                var instruction = Method.Body.Instructions [i];

                if (BlockList.TryGetBlock(instruction, out var newBB))
                {
                    if (bb != null && bb.BranchType != BranchType.None)
                    {
                        throw DebugHelpers.AssertFail(Method, bb, $"Found known basic block with unexpected branch type `{bb.BranchType}`");
                    }
                    LogDebug(2, $"  KNOWN BB: {newBB}");
                    bb = newBB;
                }
                else if (bb == null)
                {
                    bb = BlockList.NewBlock(instruction);
                    LogDebug(2, $"  NEW BB: {bb}");
                }
                else
                {
                    bb.AddInstruction(instruction);
                }

                var type = CecilHelper.GetBranchType(instruction);
                LogDebug(2, $"    {type}: {CecilHelper.Format (instruction)}");

                if (instruction.OpCode.OperandType == OperandType.InlineMethod)
                {
                    if (LinkerConditional.Scan(this, ref bb, ref i, instruction))
                    {
                        FoundConditionals = true;
                    }
                    continue;
                }

                switch (type)
                {
                case BranchType.None:
                    break;

                case BranchType.Conditional:
                case BranchType.False:
                case BranchType.True:
                case BranchType.Jump:
                    BlockList.AddJumpOrigin(bb, instruction, (Instruction)instruction.Operand);
                    bb = null;
                    break;

                case BranchType.Exit:
                case BranchType.Return:
                case BranchType.EndFinally:
                    bb = null;
                    break;

                case BranchType.Switch:
                    foreach (var label in (Instruction [])bb.LastInstruction.Operand)
                    {
                        BlockList.AddJumpOrigin(bb, instruction, label);
                    }
                    bb = null;
                    break;

                default:
                    throw new OptimizerAssertionException();
                }
            }

            BlockList.ComputeOffsets();

            DumpBlocks();

            if (Context.Options.AnalyzeAll || FoundConditionals || DebugLevel > 3)
            {
                EliminateDeadBlocks();
                DumpBlocks();
                return(true);
            }

            return(true);
        }
Пример #7
0
 internal void LogDebug(int level, string indent, string message, IReadOnlyCollection <Instruction> collection)
 {
     LogDebug(level, indent, message, collection, i => CecilHelper.Format(i));
 }
        public bool RemoveDeadBlocks()
        {
            Scanner.LogDebug(2, $"REMOVE DEAD BLOCKS: {Method.Name}");
            Scanner.DumpBlocks(2);

            var foundDeadBlocks = false;

            for (int i = 0; i < BlockList.Count; i++)
            {
                var block = BlockList [i];
                if (!block.IsDead)
                {
                    continue;
                }

                Scanner.LogDebug(2, $"  FOUND DEAD BLOCK: {block}");

                if (CecilHelper.IsBranch(block.BranchType))
                {
                    var target = BlockList.GetBlock((Instruction)block.LastInstruction.Operand);
                    target.RemoveJumpOrigin(block.LastInstruction);
                }

                if (block.ExceptionHandlers.Count > 0)
                {
                    CheckRemoveExceptionBlock(ref i);
                }

                foundDeadBlocks = true;
            }

            Scanner.LogDebug(2, $"REMOVE DEAD BLOCKS #1: {Method.Name} {foundDeadBlocks}");

            if (!foundDeadBlocks)
            {
                return(false);
            }

            var removedDeadBlocks = false;

            for (int i = 0; i < BlockList.Count; i++)
            {
                var block = BlockList [i];
                if (!block.IsDead)
                {
                    continue;
                }

                Scanner.LogDebug(2, $"  DELETING DEAD BLOCK: {block}");

                BlockList.DeleteBlock(ref block);
                removedDeadBlocks = true;
                i--;
            }

            if (removedDeadBlocks)
            {
                BlockList.ComputeOffsets();

                Scanner.LogDebug(2, $"REMOVE DEAD BLOCKS DONE: {Method.Name} {foundDeadBlocks}");
                Scanner.DumpBlocks(2);

                Scanner.Context.Options.OptimizerReport?.RemovedDeadBlocks(Method);
            }

            return(removedDeadBlocks);
        }
        void RemoveVariable(VariableEntry variable)
        {
            if (Scanner.DebugLevel > 1)
            {
                BlockList.ComputeOffsets();
                Scanner.LogDebug(2, $"DELETE VARIABLE: {Method.Name} {variable}");
                Scanner.DumpBlocks(2);
            }

            for (int i = 0; i < BlockList.Count; i++)
            {
                var block = BlockList [i];
                for (int j = 0; j < block.Instructions.Count; j++)
                {
                    var instruction = block.Instructions [j];
                    Scanner.LogDebug(2, $"    {CecilHelper.Format (instruction)}");

                    switch (instruction.OpCode.Code)
                    {
                    case Code.Ldloc_0:
                        if (variable.Index == 0 && variable.IsConstant)
                        {
                            BlockList.ReplaceInstructionAt(ref block, j, CecilHelper.CreateConstantLoad(variable.Value));
                        }
                        break;

                    case Code.Stloc_0:
                        break;

                    case Code.Ldloc_1:
                        if (variable.Index < 1)
                        {
                            BlockList.ReplaceInstructionAt(ref block, j, Instruction.Create(OpCodes.Ldloc_0));
                        }
                        else if (variable.Index == 1)
                        {
                            BlockList.ReplaceInstructionAt(ref block, j, CecilHelper.CreateConstantLoad(variable.Value));
                        }
                        break;

                    case Code.Stloc_1:
                        if (variable.Index < 1)
                        {
                            BlockList.ReplaceInstructionAt(ref block, j, Instruction.Create(OpCodes.Stloc_0));
                        }
                        break;

                    case Code.Ldloc_2:
                        if (variable.Index < 2)
                        {
                            BlockList.ReplaceInstructionAt(ref block, j, Instruction.Create(OpCodes.Ldloc_1));
                        }
                        else if (variable.Index == 2)
                        {
                            BlockList.ReplaceInstructionAt(ref block, j, CecilHelper.CreateConstantLoad(variable.Value));
                        }
                        break;

                    case Code.Stloc_2:
                        if (variable.Index < 2)
                        {
                            BlockList.ReplaceInstructionAt(ref block, j, Instruction.Create(OpCodes.Stloc_1));
                        }
                        break;

                    case Code.Ldloc_3:
                        if (variable.Index < 3)
                        {
                            BlockList.ReplaceInstructionAt(ref block, j, Instruction.Create(OpCodes.Ldloc_2));
                        }
                        else if (variable.Index == 3)
                        {
                            BlockList.ReplaceInstructionAt(ref block, j, CecilHelper.CreateConstantLoad(variable.Value));
                        }
                        break;

                    case Code.Stloc_3:
                        if (variable.Index < 3)
                        {
                            BlockList.ReplaceInstructionAt(ref block, j, Instruction.Create(OpCodes.Stloc_2));
                        }
                        break;

                    case Code.Ldloc:
                    case Code.Ldloc_S:
                        var argument = CecilHelper.GetVariable(Method.Body, instruction);
                        if (argument == variable.Variable)
                        {
                            BlockList.ReplaceInstructionAt(ref block, j, CecilHelper.CreateConstantLoad(variable.Value));
                        }
                        break;
                    }
                }
            }

            if (Scanner.DebugLevel > 1)
            {
                BlockList.ComputeOffsets();
                Scanner.LogDebug(2, $"DELETE VARIABLE DONE: {Method.Name} {variable}");
                Scanner.DumpBlocks(2);
            }
        }
Пример #10
0
        public bool RemoveUnusedVariables()
        {
            Scanner.LogDebug(1, $"REMOVE VARIABLES: {Method.Name}");

            if (Method.Body.HasExceptionHandlers)
            {
                return(false);
            }

            var removed   = false;
            var variables = new Dictionary <VariableDefinition, VariableEntry> ();

            for (int i = 0; i < Method.Body.Variables.Count; i++)
            {
                var variable = new VariableEntry(Method.Body.Variables [i], i);
                variables.Add(variable.Variable, variable);

                if (Scanner.DebugLevel > 1)
                {
                    Scanner.LogDebug(2, $"  VARIABLE: {variable}");
                }
            }

            foreach (var block in BlockList.Blocks)
            {
                Scanner.LogDebug(2, $"REMOVE VARIABLES #1: {block}");

                for (int i = 0; i < block.Instructions.Count; i++)
                {
                    var instruction = block.Instructions [i];
                    Scanner.LogDebug(2, $"    {CecilHelper.Format (instruction)}");

                    var variable = CecilHelper.GetVariable(Method.Body, instruction);
                    if (variable == null)
                    {
                        continue;
                    }

                    var entry = variables [variable];
                    if (entry == null)
                    {
                        throw DebugHelpers.AssertFail(Method, block, $"Cannot resolve variable from instruction `{CecilHelper.Format (instruction)}`.");
                    }

                    entry.Used = true;
                    if (entry.Modified)
                    {
                        continue;
                    }

                    switch (instruction.OpCode.Code)
                    {
                    case Code.Ldloc_0:
                    case Code.Ldloc_1:
                    case Code.Ldloc_2:
                    case Code.Ldloc_3:
                    case Code.Ldloc:
                    case Code.Ldloc_S:
                        continue;

                    case Code.Ldloca:
                    case Code.Ldloca_S:
                        entry.SetModified();
                        continue;

                    case Code.Stloc:
                    case Code.Stloc_0:
                    case Code.Stloc_1:
                    case Code.Stloc_2:
                    case Code.Stloc_3:
                    case Code.Stloc_S:
                        break;

                    default:
                        throw DebugHelpers.AssertFailUnexpected(Method, block, instruction);
                    }

                    if (i == 0 || entry.IsConstant)
                    {
                        entry.SetModified();
                        continue;
                    }

                    var load = block.Instructions [i - 1];
                    switch (block.Instructions [i - 1].OpCode.Code)
                    {
                    case Code.Ldc_I4_0:
                        entry.SetConstant(block, load, ConstantValue.Zero);
                        break;

                    case Code.Ldc_I4_1:
                        entry.SetConstant(block, load, ConstantValue.One);
                        break;

                    case Code.Ldnull:
                        entry.SetConstant(block, load, ConstantValue.Null);
                        break;

                    default:
                        entry.SetModified();
                        break;
                    }
                }
            }

            Scanner.LogDebug(1, $"REMOVE VARIABLES #1");

            for (int i = Method.Body.Variables.Count - 1; i >= 0; i--)
            {
                var variable = variables [Method.Body.Variables [i]];
                Scanner.LogDebug(2, $"    VARIABLE #{i}: {variable}");
                if (!variable.Used)
                {
                    Scanner.LogDebug(2, $"    --> REMOVE");
                    Scanner.LogDebug(1, $"REMOVE VARIABLES - REMOVE: {Method.Name}");
                    RemoveVariable(variable);
                    Method.Body.Variables.RemoveAt(i);
                    removed = true;
                    continue;
                }

                if (variable.IsConstant)
                {
                    Scanner.LogDebug(2, $"    --> CONSTANT ({variable.Value}): {variable.Instruction}");
                    Scanner.LogDebug(1, $"REMOVE VARIABLES - CONSTANT: {Method.Name}");
                    Scanner.DumpBlock(2, variable.Block);
                    var position = variable.Block.IndexOf(variable.Instruction);
                    var block    = variable.Block;
                    BlockList.RemoveInstructionAt(ref block, position + 1);
                    BlockList.RemoveInstructionAt(ref block, position);
                    RemoveVariable(variable);
                    Method.Body.Variables.RemoveAt(i);
                    removed = true;
                    continue;
                }
            }

            if (removed)
            {
                BlockList.ComputeOffsets();

                Scanner.LogDebug(1, $"REMOVE VARIABLES DONE: {removed}");
                Scanner.DumpBlocks(1);

                Scanner.Context.Options.OptimizerReport?.RemovedDeadVariables(Method);
            }

            return(removed);
        }
Пример #11
0
 void Update()
 {
     BranchType = CecilHelper.GetBranchType(LastInstruction);
 }
Пример #12
0
        public static VariableDefinition GetVariable(MethodBody body, Instruction instruction)
        {
            switch (instruction.OpCode.Code)
            {
            case Code.Ldloc_0:
            case Code.Stloc_0:
                return(body.Variables [0]);

            case Code.Ldloc_1:
            case Code.Stloc_1:
                return(body.Variables [1]);

            case Code.Ldloc_2:
            case Code.Stloc_2:
                return(body.Variables [2]);

            case Code.Ldloc_3:
            case Code.Stloc_3:
                return(body.Variables [3]);

            case Code.Ldloc:
            case Code.Ldloc_S:
            case Code.Ldloca:
            case Code.Ldloca_S:
            case Code.Stloc_S:
            case Code.Stloc:
                var variable = ((VariableReference)instruction.Operand).Resolve();
                if (variable == null)
                {
                    throw DebugHelpers.AssertFail(body.Method, $"Unable to resolve variable from `{CecilHelper.Format (instruction)}`");
                }
                return(variable);

            default:
                return(null);
            }
        }