public void Rewriter(ILProcessor processor) { var branches = processor.Instructions .OfType <OperandInstruction <ILProcessorInstruction> >() .Where(i => OpCodesMap.ContainsKey(i.OpCode)) .ToList(); if (!branches.Any()) { return; } var offsets = new Dictionary <ILProcessorInstruction, int>(); var curOffset = 0; foreach (var instruction in processor.Instructions) { offsets.Add(instruction, curOffset); curOffset += GetInstructionSize(instruction); } while (branches.Any()) { var branch = branches.FirstOrDefault(i => { var deltaOffset = offsets[i.Operand] - offsets[i.Next]; return(deltaOffset >= sbyte.MinValue && deltaOffset <= sbyte.MaxValue); }); if (branch == null) { break; } var shortFormOpCode = OpCodesMap[branch.OpCode]; var shortBranch = OperandInstruction.Create(shortFormOpCode, branch.Operand); processor.Replace(branch, shortBranch); //Update offsets ILProcessorInstruction loop = shortBranch; curOffset = offsets[branch]; while (loop != null) { offsets[loop] = curOffset; curOffset += GetInstructionSize(loop); loop = loop.Next; } offsets.Remove(branch); branches.Remove(branch); } }
private static int GetInstructionSize(ILProcessorInstruction instruction) { var size = instruction.OpCode.Size; switch (instruction.OpCode.OperandType) { case OperandType.InlineNone: break; case OperandType.ShortInlineBrTarget: case OperandType.ShortInlineI: case OperandType.ShortInlineVar: size += 1; break; case OperandType.InlineVar: size += 2; break; case OperandType.InlineBrTarget: case OperandType.InlineI: case OperandType.ShortInlineR: case OperandType.InlineString: case OperandType.InlineSig: case OperandType.InlineMethod: case OperandType.InlineField: case OperandType.InlineType: case OperandType.InlineTok: size += 4; break; case OperandType.InlineI8: case OperandType.InlineR: size += 8; break; case OperandType.InlineSwitch: size += 4 + 4 * ((OperandInstruction <IReadOnlyList <ILProcessorInstruction> >)instruction).Operand.Count; break; default: throw new ArgumentOutOfRangeException(); } return(size); }
/// <summary> /// Returns the overall effect of the given instruction on the stack. /// Negative numbers means the stack shrinks, positive the stack grows /// </summary> /// <param name="instruction"></param> /// <returns></returns> private static int GetStackDelta(ILProcessorInstruction instruction) { var method = (instruction as OperandInstruction <MethodBase>)?.Operand; var stackDelta = 0; switch (instruction.OpCode.StackBehaviourPop) { case StackBehaviour.Pop0: break; case StackBehaviour.Pop1: case StackBehaviour.Popi: case StackBehaviour.Popref: stackDelta -= 1; break; case StackBehaviour.Pop1_pop1: case StackBehaviour.Popi_pop1: case StackBehaviour.Popi_popi: case StackBehaviour.Popi_popi8: case StackBehaviour.Popi_popr4: case StackBehaviour.Popi_popr8: case StackBehaviour.Popref_pop1: case StackBehaviour.Popref_popi: stackDelta -= 2; break; case StackBehaviour.Popi_popi_popi: case StackBehaviour.Popref_popi_pop1: case StackBehaviour.Popref_popi_popi: case StackBehaviour.Popref_popi_popi8: case StackBehaviour.Popref_popi_popr4: case StackBehaviour.Popref_popi_popr8: case StackBehaviour.Popref_popi_popref: stackDelta -= 3; break; case StackBehaviour.Varpop: if (method?.IsStatic == false) { stackDelta -= 1; } stackDelta -= method?.GetParameters().Length ?? 0; break; default: throw new ArgumentOutOfRangeException(); } switch (instruction.OpCode.StackBehaviourPush) { case StackBehaviour.Push0: break; case StackBehaviour.Push1: case StackBehaviour.Pushi: case StackBehaviour.Pushi8: case StackBehaviour.Pushr4: case StackBehaviour.Pushr8: case StackBehaviour.Pushref: stackDelta += 1; break; case StackBehaviour.Push1_push1: stackDelta += 2; break; case StackBehaviour.Varpush: if ((method as MethodInfo)?.ReturnType != typeof(void)) { stackDelta += 1; } break; default: throw new ArgumentOutOfRangeException(); } return(stackDelta); }