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 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 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 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); }
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 (); } }
public void Emit (OpCode opcode, Instruction [] targets) { Append (Create (opcode, targets)); }
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); }
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 Remove (Instruction instruction) { if (instruction == null) throw new ArgumentNullException ("instruction"); if (!instructions.Remove (instruction)) throw new ArgumentOutOfRangeException ("instruction"); }
static void AppendLabel (StringBuilder builder, Instruction instruction) { builder.Append ("IL_"); builder.Append (instruction.offset.ToString ("x4")); }
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 Append (Instruction instruction) { if (instruction == null) throw new ArgumentNullException ("instruction"); instructions.Add (instruction); }
public void InsertAfter (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 + 1, instruction); }
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; } }
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); }
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; } }
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 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); }
int GetTargetOffset (Instruction instruction) { if (instruction == null) { var last = body.instructions [body.instructions.size - 1]; return last.offset + last.GetSize (); } return instruction.offset; }
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; } } }
public Instruction Create (OpCode opcode, Instruction [] targets) { return Instruction.Create (opcode, targets); }