public CurveComponent(Component parent, OptimizationWorker optimizationWorker, Specification specification) : base(parent) { if (optimizationWorker == null) { throw new ArgumentNullException("optimizationWorker"); } this.curveOptimizer = new CurveOptimizer(optimizationWorker, specification); this.curveOptimizer.CurveChanged += CurveChanged; this.curveStartComponent = new FixedPositionComponent(this, this, 0); this.curveEndComponent = new FixedPositionComponent(this, this, 1); this.specificationComponents = new List <SpecificationComponent>(); this.segmentComponents = new List <SegmentComponent>(); nextSpecification = specification.BasicSpecification; curve = null; RebuildSegmentComponents(); curveOptimizer.Submit(nextSpecification); IEnumerable <SpecificationComponent> specificationComponents = ( from spec in nextSpecification.CurveSpecifications orderby spec.Position ascending group spec by spec.Position into specificationGroup select new SpecificationComponent(this, this, specificationGroup.Key, specificationGroup) ); foreach (SpecificationComponent component in specificationComponents) { AddSpecificationComponent(component); } }
/// <summary> /// Performs the optimization starting at the current instruction. /// </summary> /// <param name="instruction">The instruction to target.</param> /// <param name="worker">The worker for optimization actions.</param> public override void OptimizeInstruction(Instruction instruction, OptimizationWorker worker) { // TODO: allow arguments // TODO: allow return values // TODO: allow generic methods // TODO: allow non-static methods var opCode = instruction.OpCode; if (opCode.FlowControl != FlowControl.Call) { return; } var methodRef = (MethodReference) instruction.Operand; var typeRef = methodRef.DeclaringType; var module = typeRef.Module; var type = module.Types[typeRef.FullName]; if (type == null) { return; } var method = type.Methods.GetMethod(methodRef.Name, methodRef.Parameters); bool shouldInlineMethod; if (!this.shouldInline.TryGetValue(method, out shouldInlineMethod)) { shouldInlineMethod = this.configuration.ShouldInline(method); this.shouldInline[method] = shouldInlineMethod; } if (shouldInlineMethod) { InlineMethod(instruction, worker, method); } }
/// <summary> /// Performs the optimization starting at the current instruction. /// </summary> /// <param name="instruction">The instruction to target.</param> /// <param name="worker">The worker for optimization actions.</param> public override void OptimizeInstruction(Instruction instruction, OptimizationWorker worker) { var opCode = instruction.OpCode; if (opCode.Code == Code.Nop) { worker.DeleteInstruction(instruction); } }
public CurveOptimizer(OptimizationWorker optimizationWorker, Specification specification) { if (optimizationWorker == null) { throw new ArgumentNullException("optimizationWorker"); } this.optimizer = new Optimizer(); this.optimizationWorker = optimizationWorker; this.specification = specification; }
/// <summary> /// Performs the optimization starting at the current instruction. /// </summary> /// <param name="instruction">The instruction to target.</param> /// <param name="worker">The worker for optimization actions.</param> public override void OptimizeInstruction(Instruction instruction, OptimizationWorker worker) { var opCode = instruction.OpCode; if (opCode.FlowControl == FlowControl.Branch || opCode.FlowControl == FlowControl.Cond_Branch) { var target = (Instruction)instruction.Operand; if (target.OpCode.FlowControl == FlowControl.Branch) { instruction.Operand = target.Operand; } } }
/// <summary> /// Performs the optimization starting at the current instruction. /// </summary> /// <param name="instruction">The instruction to target.</param> /// <param name="worker">The worker for optimization actions.</param> public override void OptimizeInstruction(Instruction instruction, OptimizationWorker worker) { // the first instruction in a method is not dead code if (instruction.Previous == null) { return; } var sources = worker.SourceInstructions(instruction); if (sources.Count == 0) { worker.DeleteInstruction(instruction); } }
/// <summary> /// Performs the optimization starting at the current instruction. /// </summary> /// <param name="instruction">The instruction to target.</param> /// <param name="worker">The worker for optimization actions.</param> public override void OptimizeInstruction(Instruction instruction, OptimizationWorker worker) { var opCode = instruction.OpCode; if (opCode.FlowControl == FlowControl.Branch) { var target = (Instruction)instruction.Operand; var targetOpCode = target.OpCode; if (targetOpCode.FlowControl == FlowControl.Return || targetOpCode.FlowControl == FlowControl.Throw) { var replacement = worker.CilWorker.Create(targetOpCode); worker.ReplaceInstruction(instruction, replacement); } } }
/// <summary> /// Performs the optimization starting at the current instruction. /// </summary> /// <param name="instruction">The instruction to target.</param> /// <param name="worker">The worker for optimization actions.</param> public override void OptimizeInstruction(Instruction instruction, OptimizationWorker worker) { // TODO: currently if an optimization removes an instruction between a branch and its // target, this will not trigger, since the target instruction will be the one after the // branch. // This can be solved by adding a property to the optimization indicating how many // instructions ahead can affect its application. var opCode = instruction.OpCode; if (opCode.FlowControl == FlowControl.Branch || opCode.FlowControl == FlowControl.Cond_Branch) { var target = instruction.Operand as Instruction; if (target == instruction.Next) { worker.DeleteInstruction(instruction); } } }
public RootComponent(Window parentWindow, IEnumerable <string> parameters) { if (parentWindow == null) { throw new ArgumentNullException("parentWindow"); } if (parameters.Count() > 1) { throw new ArgumentException("parameter 'parameters' contained more than one item."); } this.parentWindow = parentWindow; this.optimizationWorker = new OptimizationWorker(); if (parameters.Count() == 1) { this.backgroundComponent = new BackgroundComponent(this, parameters.Single()); } this.curveComponents = new List <CurveComponent>(); }
/// <summary> /// Inlines the supplied method. /// </summary> /// <param name="callInstruction">The call instruction.</param> /// <param name="worker">The worker to use to modify the caller, positioned at the call instruction.</param> /// <param name="method">The method to inline.</param> private static void InlineMethod( Instruction callInstruction, OptimizationWorker worker, MethodDefinition method) { worker.Optimize(method); // replace the call with a nop in order to preserve branches to this call. var nop = worker.CilWorker.Create(OpCodes.Nop); worker.ReplaceInstruction(callInstruction, nop); var nextInstruction = callInstruction.Next; var instructions = method.Body.Instructions; var instructionCount = instructions.Count; if (instructionCount == 0) { // TODO: can this happen? // do all methods end with a ret instruction? return; } var instruction = instructions[0]; if (instruction.OpCode.FlowControl == FlowControl.Return) { return; } // Create local variables to be used by the inlined function var variables = method.Body.Variables; for (var i = 0; i < variables.Count; i++) { var variable = variables[i]; worker.AddLocalVariable(variable); } // TODO: try to avoid this extra dictionary. // This mapping maps an instruction to the inlined version. This is required in order to // patch up backwards branch instructions to reference an instruction in the current method. var copiedInstructions = new Dictionary<Instruction, Instruction>(); for (var i = 0; i < instructionCount; i++) { var currentInstruction = instructions[i]; int location; Instruction newInstruction; if (currentInstruction.OpCode.FlowControl == FlowControl.Return) { // return instructions now just move execution to the instruction after the call // TODO: create best form of br instruction newInstruction = worker.CilWorker.Create(OpCodes.Br, nextInstruction); } else if (currentInstruction.OpCode.FlowControl == FlowControl.Branch || currentInstruction.OpCode.FlowControl == FlowControl.Cond_Branch) { // if we are jumping to an earlier instruction in the method, then create a jump // to the cloned version. var target = (Instruction) currentInstruction.Operand; Instruction inlinedTarget; if (!copiedInstructions.TryGetValue(target, out inlinedTarget)) { inlinedTarget = target; } // TODO: if this is a short branch this may need converting to a long branch // as for example "ret" instructions may have been converted to branches in // the intervening space. newInstruction = worker.CilWorker.Create(currentInstruction.OpCode, inlinedTarget); } else if (currentInstruction.IsLdloc(out location)) { var variable = variables[location]; // TODO: create the best form of ldloc instruction newInstruction = worker.CilWorker.Create(OpCodes.Ldloc, variable); } else if (currentInstruction.IsLdloca(out location)) { var variable = variables[location]; // TODO: create the best form of ldloca instruction newInstruction = worker.CilWorker.Create(OpCodes.Ldloca, variable); } else if (currentInstruction.IsStloc(out location)) { var variable = variables[location]; // TODO: create the best form of ldloca instruction newInstruction = worker.CilWorker.Create(OpCodes.Stloc, variable); } else { newInstruction = worker.CopyInstruction(currentInstruction); } worker.InsertBefore(nextInstruction, newInstruction); copiedInstructions.Add(currentInstruction, newInstruction); worker.RetargetBranches(currentInstruction, newInstruction); } }