コード例 #1
0
        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);
            }
        }
コード例 #2
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);
        }