public void Append(Instruction instruction) { if (instruction == null) throw new ArgumentNullException("instruction"); instructions.Add(instruction); }
public void Replace(Instruction target, Instruction instruction) { if (target == null) throw new ArgumentNullException("target"); if (instruction == null) throw new ArgumentNullException("instruction"); InsertAfter(target, instruction); Remove(target); }
public void Remove(Instruction instruction) { if (instruction == null) throw new ArgumentNullException("instruction"); if (!instructions.Remove(instruction)) throw new ArgumentOutOfRangeException("instruction"); }
public static Instruction Create(OpCode opcode, Instruction[] targets) { if (targets == null) throw new ArgumentNullException("targets"); if (opcode.OperandType != OperandType.InlineSwitch) throw new ArgumentException("opcode"); return new Instruction(opcode, targets); }
int GetTargetOffset(Instruction instruction) { if (instruction == null) { var last = body.instructions[body.instructions.size - 1]; return last.offset + last.GetSize(); } return instruction.offset; }
static void CopyBranchStackSize(ref Dictionary<Instruction, int> stack_sizes, Instruction target, int stack_size) { if (stack_sizes == null) stack_sizes = new Dictionary<Instruction, int>(); int branch_stack_size = stack_size; int computed_size; if (stack_sizes.TryGetValue(target, out computed_size)) branch_stack_size = System.Math.Max(branch_stack_size, computed_size); stack_sizes[target] = branch_stack_size; }
static void ComputeStackSize(Instruction instruction, ref int stack_size) { switch (instruction.opcode.FlowControl) { case FlowControl.Branch: case FlowControl.Break: case FlowControl.Throw: case FlowControl.Return: stack_size = 0; break; } }
static void ComputeStackDelta(Instruction instruction, ref int stack_size) { switch (instruction.opcode.FlowControl) { case FlowControl.Call: { var method = (IMethodSignature)instruction.operand; // pop 'this' argument if (method.HasImplicitThis() && instruction.opcode.Code != Code.Newobj) stack_size--; // pop normal arguments if (method.HasParameters) stack_size -= method.Parameters.Count; // pop function pointer if (instruction.opcode.Code == Code.Calli) stack_size--; // push return value if (method.ReturnType.etype != ElementType.Void || instruction.opcode.Code == Code.Newobj) stack_size++; break; } default: ComputePopDelta(instruction.opcode.StackBehaviourPop, ref stack_size); ComputePushDelta(instruction.opcode.StackBehaviourPush, ref stack_size); break; } }
static void ExpandMacro(Instruction instruction, OpCode opcode, object operand) { instruction.OpCode = opcode; instruction.Operand = operand; }
private static MethodBody CloneMethodBody(MethodBody body, MethodDefinition source, MethodDefinition target) { var context = target.DeclaringType.Module; var nb = new MethodBody(target) { MaxStackSize = body.MaxStackSize, InitLocals = body.InitLocals, CodeSize = body.CodeSize }; var worker = nb.GetILProcessor(); foreach (var var in body.Variables) nb.Variables.Add(new VariableDefinition( var.Name, FixTypeImport(context, source, target, var.VariableType))); foreach (var instr in body.Instructions) { var ni = new Instruction(instr.OpCode, OpCodes.Nop); switch (instr.OpCode.OperandType) { case OperandType.InlineArg: case OperandType.ShortInlineArg: if (instr.Operand == body.ThisParameter) ni.Operand = nb.ThisParameter; else { var param = body.Method.Parameters.IndexOf((ParameterDefinition)instr.Operand); ni.Operand = target.Parameters[param]; } break; case OperandType.InlineVar: case OperandType.ShortInlineVar: var var = body.Variables.IndexOf((VariableDefinition)instr.Operand); ni.Operand = nb.Variables[var]; break; case OperandType.InlineField: ni.Operand = FixFieldImport(context, source, target, (FieldReference)instr.Operand); break; case OperandType.InlineMethod: ni.Operand = FixMethodImport(context, source, target, (MethodReference)instr.Operand); break; case OperandType.InlineType: ni.Operand = FixTypeImport(context, source, target, (TypeReference)instr.Operand); break; case OperandType.InlineTok: if ((instr.Operand) is TypeReference) ni.Operand = FixTypeImport(context, source, target, (TypeReference)instr.Operand); else if ((instr.Operand) is FieldReference) ni.Operand = FixFieldImport(context, source, target, (FieldReference)instr.Operand); else if ((instr.Operand) is MethodReference) ni.Operand = FixMethodImport(context, source, target, (MethodReference)instr.Operand); break; case OperandType.ShortInlineBrTarget: case OperandType.InlineBrTarget: case OperandType.InlineSwitch: break; default: ni.Operand = instr.Operand; break; } worker.Append(ni); } for (var i = 0; i < body.Instructions.Count; i++) { var instr = nb.Instructions[i]; var oldi = body.Instructions[i]; switch (instr.OpCode.OperandType) { case OperandType.InlineSwitch: { var olds = (Instruction[])oldi.Operand; var targets = new Instruction[olds.Length]; for (var j = 0; j < targets.Length; j++) targets[j] = GetInstruction(body, nb, olds[j]); instr.Operand = targets; } break; case OperandType.InlineBrTarget: case OperandType.ShortInlineBrTarget: instr.Operand = GetInstruction(body, nb, (Instruction)oldi.Operand); break; } } foreach (var eh in body.ExceptionHandlers) { var neh = new ExceptionHandler(eh.HandlerType) { TryStart = GetInstruction(body, nb, eh.TryStart), TryEnd = GetInstruction(body, nb, eh.TryEnd), HandlerStart = GetInstruction(body, nb, eh.HandlerStart), HandlerEnd = GetInstruction(body, nb, eh.HandlerEnd) }; switch (eh.HandlerType) { case ExceptionHandlerType.Catch: neh.CatchType = FixTypeImport(context, source, target, eh.CatchType); break; case ExceptionHandlerType.Filter: neh.FilterStart = GetInstruction(body, nb, eh.FilterStart); break; } nb.ExceptionHandlers.Add(neh); } return nb; }
internal static Instruction GetInstruction(MethodBody oldBody, MethodBody newBody, Instruction i) { int pos = oldBody.Instructions.IndexOf(i); if (pos > -1 && pos < newBody.Instructions.Count) return newBody.Instructions[pos]; return new Instruction(int.MaxValue, OpCodes.Nop); }
void ResolveBranches(Collection<Instruction> instructions) { var items = instructions.items; var size = instructions.size; for (int i = 0; i < size; i++) { var instruction = items[i]; switch (instruction.opcode.OperandType) { case OperandType.ShortInlineBrTarget: case OperandType.InlineBrTarget: instruction.operand = GetInstruction((int)instruction.operand); break; case OperandType.InlineSwitch: var offsets = (int[])instruction.operand; var branches = new Instruction[offsets.Length]; for (int j = 0; j < offsets.Length; j++) branches[j] = GetInstruction(offsets[j]); instruction.operand = branches; break; } } }
object ReadOperand(Instruction instruction) { switch (instruction.opcode.OperandType) { case OperandType.InlineSwitch: var length = ReadInt32(); var base_offset = Offset + (4 * length); var branches = new int[length]; for (int i = 0; i < length; i++) branches[i] = base_offset + ReadInt32(); return branches; case OperandType.ShortInlineBrTarget: return ReadSByte() + Offset; case OperandType.InlineBrTarget: return ReadInt32() + Offset; case OperandType.ShortInlineI: if (instruction.opcode == OpCodes.Ldc_I4_S) return ReadSByte(); return ReadByte(); case OperandType.InlineI: return ReadInt32(); case OperandType.ShortInlineR: return ReadSingle(); case OperandType.InlineR: return ReadDouble(); case OperandType.InlineI8: return ReadInt64(); case OperandType.ShortInlineVar: return GetVariable(ReadByte()); case OperandType.InlineVar: return GetVariable(ReadUInt16()); case OperandType.ShortInlineArg: return GetParameter(ReadByte()); case OperandType.InlineArg: return GetParameter(ReadUInt16()); case OperandType.InlineSig: return GetCallSite(ReadToken()); case OperandType.InlineString: return GetString(ReadToken()); case OperandType.InlineTok: case OperandType.InlineType: case OperandType.InlineMethod: case OperandType.InlineField: return reader.LookupToken(ReadToken()); default: throw new NotSupportedException(); } }
void ReadCode() { start = position; var code_size = body.code_size; if (code_size < 0 || buffer.Length <= (uint)(code_size + position)) code_size = 0; var end = start + code_size; var instructions = body.instructions = new InstructionCollection((code_size + 1) / 2); while (position < end) { var offset = base.position - start; var opcode = ReadOpCode(); var current = new Instruction(offset, opcode); if (opcode.OperandType != OperandType.InlineNone) current.operand = ReadOperand(current); instructions.Add(current); } ResolveBranches(instructions); }
static void AppendLabel(StringBuilder builder, Instruction instruction) { builder.Append("IL_"); builder.Append(instruction.offset.ToString("x4")); }
static void MakeMacro(Instruction instruction, OpCode opcode) { instruction.OpCode = opcode; instruction.Operand = null; }
static void AddExceptionStackSize(Instruction handler_start, ref Dictionary<Instruction, int> stack_sizes) { if (handler_start == null) return; if (stack_sizes == null) stack_sizes = new Dictionary<Instruction, int>(); stack_sizes[handler_start] = 1; }
static bool OptimizeBranch(Instruction instruction) { var offset = ((Instruction)instruction.Operand).Offset - (instruction.Offset + instruction.OpCode.Size + 4); if (!(offset >= -128 && offset <= 127)) return false; switch (instruction.OpCode.Code) { case Code.Br: instruction.OpCode = OpCodes.Br_S; break; case Code.Brfalse: instruction.OpCode = OpCodes.Brfalse_S; break; case Code.Brtrue: instruction.OpCode = OpCodes.Brtrue_S; break; case Code.Beq: instruction.OpCode = OpCodes.Beq_S; break; case Code.Bge: instruction.OpCode = OpCodes.Bge_S; break; case Code.Bgt: instruction.OpCode = OpCodes.Bgt_S; break; case Code.Ble: instruction.OpCode = OpCodes.Ble_S; break; case Code.Blt: instruction.OpCode = OpCodes.Blt_S; break; case Code.Bne_Un: instruction.OpCode = OpCodes.Bne_Un_S; break; case Code.Bge_Un: instruction.OpCode = OpCodes.Bge_Un_S; break; case Code.Bgt_Un: instruction.OpCode = OpCodes.Bgt_Un_S; break; case Code.Ble_Un: instruction.OpCode = OpCodes.Ble_Un_S; break; case Code.Blt_Un: instruction.OpCode = OpCodes.Blt_Un_S; break; case Code.Leave: instruction.OpCode = OpCodes.Leave_S; break; } return true; }
static void ComputeStackSize(Instruction instruction, ref Dictionary<Instruction, int> stack_sizes, ref int stack_size, ref int max_stack) { int computed_size; if (stack_sizes != null && stack_sizes.TryGetValue(instruction, out computed_size)) stack_size = computed_size; max_stack = System.Math.Max(max_stack, stack_size); ComputeStackDelta(instruction, ref stack_size); max_stack = System.Math.Max(max_stack, stack_size); CopyBranchStackSize(instruction, ref stack_sizes, stack_size); ComputeStackSize(instruction, ref stack_size); }
public Instruction Create(OpCode opcode, Instruction[] targets) { return Instruction.Create(opcode, targets); }
static void CopyBranchStackSize(Instruction instruction, ref Dictionary<Instruction, int> stack_sizes, int stack_size) { if (stack_size == 0) return; switch (instruction.opcode.OperandType) { case OperandType.ShortInlineBrTarget: case OperandType.InlineBrTarget: CopyBranchStackSize(ref stack_sizes, (Instruction)instruction.operand, stack_size); break; case OperandType.InlineSwitch: var targets = (Instruction[])instruction.operand; for (int i = 0; i < targets.Length; i++) CopyBranchStackSize(ref stack_sizes, targets[i], stack_size); break; } }
public void Emit(OpCode opcode, Instruction[] targets) { Append(Create(opcode, targets)); }
static bool IsFatRange(Instruction start, Instruction end) { if (start == null) throw new ArgumentException(); if (end == null) return true; return end.Offset - start.Offset > 255 || start.Offset > 65535; }
public void InsertBefore(Instruction target, Instruction instruction) { if (target == null) throw new ArgumentNullException("target"); if (instruction == null) throw new ArgumentNullException("instruction"); var index = instructions.IndexOf(target); if (index == -1) throw new ArgumentOutOfRangeException("target"); instructions.Insert(index, instruction); }
void WriteOperand(Instruction instruction) { var opcode = instruction.opcode; var operand_type = opcode.OperandType; if (operand_type == OperandType.InlineNone) return; var operand = instruction.operand; if (operand == null) throw new ArgumentException(); switch (operand_type) { case OperandType.InlineSwitch: { var targets = (Instruction[])operand; WriteInt32(targets.Length); var diff = instruction.Offset + opcode.Size + (4 * (targets.Length + 1)); for (int i = 0; i < targets.Length; i++) WriteInt32(GetTargetOffset(targets[i]) - diff); break; } case OperandType.ShortInlineBrTarget: { var target = (Instruction)operand; WriteSByte((sbyte)(GetTargetOffset(target) - (instruction.Offset + opcode.Size + 1))); break; } case OperandType.InlineBrTarget: { var target = (Instruction)operand; WriteInt32(GetTargetOffset(target) - (instruction.Offset + opcode.Size + 4)); break; } case OperandType.ShortInlineVar: WriteByte((byte)GetVariableIndex((VariableDefinition)operand)); break; case OperandType.ShortInlineArg: WriteByte((byte)GetParameterIndex((ParameterDefinition)operand)); break; case OperandType.InlineVar: WriteInt16((short)GetVariableIndex((VariableDefinition)operand)); break; case OperandType.InlineArg: WriteInt16((short)GetParameterIndex((ParameterDefinition)operand)); break; case OperandType.InlineSig: WriteMetadataToken(GetStandAloneSignature((CallSite)operand)); break; case OperandType.ShortInlineI: if (opcode == OpCodes.Ldc_I4_S) WriteSByte((sbyte)operand); else WriteByte((byte)operand); break; case OperandType.InlineI: WriteInt32((int)operand); break; case OperandType.InlineI8: WriteInt64((long)operand); break; case OperandType.ShortInlineR: WriteSingle((float)operand); break; case OperandType.InlineR: WriteDouble((double)operand); break; case OperandType.InlineString: WriteMetadataToken( new MetadataToken( TokenType.String, GetUserStringIndex((string)operand))); break; case OperandType.InlineType: case OperandType.InlineField: case OperandType.InlineMethod: case OperandType.InlineTok: WriteMetadataToken(metadata.LookupToken((IMetadataTokenProvider)operand)); break; default: throw new ArgumentException(); } }
public static Instruction Create(OpCode opcode, Instruction target) { if (target == null) throw new ArgumentNullException("target"); if (opcode.OperandType != OperandType.InlineBrTarget && opcode.OperandType != OperandType.ShortInlineBrTarget) throw new ArgumentException("opcode"); return new Instruction(opcode, target); }