public void Append(Instruction instruction) { if (instruction == null) throw new ArgumentNullException ("instruction"); instructions.Add (instruction); }
static void WriteInstruction(TextWriter writer, Instruction instruction) { writer.Write (FormatLabel (instruction.Offset)); writer.Write (": "); writer.Write (instruction.OpCode.Name); if (null != instruction.Operand) { writer.Write (' '); WriteOperand (writer, instruction.Operand); } }
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); }
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 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); }
public Instruction Create(OpCode opcode, Instruction [] targets) { return Instruction.Create (opcode, targets); }
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 (); } }
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 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; }
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 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; } }
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 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); }
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 AppendLabel(StringBuilder builder, Instruction instruction) { builder.Append ("IL_"); builder.Append (instruction.offset.ToString ("x4")); }
static void ExpandMacro(Instruction instruction, OpCode opcode, object operand) { instruction.OpCode = opcode; instruction.Operand = operand; }
static void MakeMacro(Instruction instruction, OpCode opcode) { instruction.OpCode = opcode; instruction.Operand = null; }
int GetTargetOffset(Instruction instruction) { if (instruction == null) { var last = body.instructions [body.instructions.size - 1]; return last.offset + last.GetSize (); } return instruction.offset; }
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); }
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 (); } }
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; } } }
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; }
public void Emit(OpCode opcode, Instruction [] targets) { Append (Create (opcode, targets)); }
static void WriteLabelList(TextWriter writer, Instruction [] instructions) { writer.Write ("("); for (int i = 0; i < instructions.Length; i++) { if (i != 0) writer.Write (", "); writer.Write (FormatLabel (instructions [i].Offset)); } writer.Write (")"); }
public void Remove(Instruction instruction) { if (instruction == null) throw new ArgumentNullException ("instruction"); if (!instructions.Remove (instruction)) throw new ArgumentOutOfRangeException ("instruction"); }
public static string FormatInstruction(Instruction instruction) { var writer = new StringWriter (); WriteInstruction (writer, instruction); return writer.ToString (); }
static string FormatLabel(Instruction instruction) { return FormatLabel (instruction.Offset); }
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); }