Esempio n. 1
0
        protected static void SetTypeAction(XElement element, TypeAction action)
        {
            switch (action)
            {
            case TypeAction.None:
                break;

            case TypeAction.Debug:
                element.SetAttributeValue("action", "debug");
                break;

            case TypeAction.Warn:
                element.SetAttributeValue("action", "warn");
                break;

            case TypeAction.Fail:
                element.SetAttributeValue("action", "fail");
                break;

            case TypeAction.Preserve:
                element.SetAttributeValue("action", "preserve");
                break;

            case TypeAction.Size:
                element.SetAttributeValue("action", "size");
                break;

            default:
                throw DebugHelpers.AssertFail($"Invalid type action: `{action}`.");
            }
        }
        public void MarkAsConstantMethod(MethodDefinition method, ConstantValue value)
        {
            if (!IsEnabled(ReportMode.Actions))
            {
                return;
            }
            switch (value)
            {
            case ConstantValue.False:
                ActionList.GetMethod(method, true, MethodAction.ReturnFalse);
                break;

            case ConstantValue.True:
                ActionList.GetMethod(method, true, MethodAction.ReturnTrue);
                break;

            case ConstantValue.Null:
                ActionList.GetMethod(method, true, MethodAction.ReturnNull);
                break;

            case ConstantValue.Throw:
                ActionList.GetMethod(method, true, MethodAction.Throw);
                break;

            default:
                throw DebugHelpers.AssertFail($"Invalid constant value: `{value}`.");
            }
        }
Esempio n. 3
0
        protected static void SetMethodAction(XElement element, MethodAction action)
        {
            switch (action)
            {
            case MethodAction.None:
                break;

            case MethodAction.Scan:
                element.SetAttributeValue("action", "scan");
                break;

            case MethodAction.Debug:
                element.SetAttributeValue("action", "debug");
                break;

            case MethodAction.Warn:
                element.SetAttributeValue("action", "warn");
                break;

            case MethodAction.Fail:
                element.SetAttributeValue("action", "fail");
                break;

            case MethodAction.ReturnFalse:
                element.SetAttributeValue("action", "return-false");
                break;

            case MethodAction.ReturnTrue:
                element.SetAttributeValue("action", "return-true");
                break;

            case MethodAction.ReturnNull:
                element.SetAttributeValue("action", "return-null");
                break;

            case MethodAction.Throw:
                element.SetAttributeValue("action", "throw");
                break;

            default:
                throw DebugHelpers.AssertFail($"Invalid method action: `{action}`.");
            }
        }
Esempio n. 4
0
        public static Instruction CreateConstantLoad(ConstantValue value)
        {
            switch (value)
            {
            case ConstantValue.Null:
                return(Instruction.Create(OpCodes.Ldnull));

            case ConstantValue.False:
            case ConstantValue.Zero:
                return(Instruction.Create(OpCodes.Ldc_I4_0));

            case ConstantValue.True:
            case ConstantValue.One:
                return(Instruction.Create(OpCodes.Ldc_I4_1));

            default:
                throw DebugHelpers.AssertFail($"Invalid constant valud `{value}`.");
            }
        }
Esempio n. 5
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);
            }
        }
Esempio n. 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);
        }
        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);
        }