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}`."); } }
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}`."); } }
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}`."); } }
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); } }
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); }