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); } }
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 (); } }
static void WriteLabelList(ITextOutput writer, Instruction[] instructions) { writer.Write("("); for(int i = 0; i < instructions.Length; i++) { if(i != 0) writer.Write(", "); WriteOffsetReference(writer, instructions[i]); } writer.Write(")"); }
public static void WriteOffsetReference(ITextOutput writer, Instruction instruction) { writer.WriteReference(CecilExtensions.OffsetToString(instruction.Offset), instruction); }
static void AppendLabel (StringBuilder builder, Instruction instruction) { builder.Append ("IL_"); builder.Append (instruction.offset.ToString ("x4")); }
static void ComputeStackDelta (Instruction instruction, ref int stack_size) { switch (instruction.opcode.FlowControl) { case FlowControl.Call: { var method = (IMethodSignature) instruction.operand; stack_size -= (method.HasParameters ? method.Parameters.Count : 0) + (method.HasThis && instruction.opcode.Code != Code.Newobj ? 1 : 0); stack_size += (method.ReturnType.etype == ElementType.Void ? 0 : 1) + (method.HasThis && instruction.opcode.Code == Code.Newobj ? 1 : 0); break; } default: ComputePopDelta (instruction.opcode.StackBehaviourPop, ref stack_size); ComputePushDelta (instruction.opcode.StackBehaviourPush, ref 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 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 static string FormatInstruction (Instruction instruction) { var writer = new StringWriter (); WriteInstruction (writer, instruction); return writer.ToString (); }
internal ControlFlowNode(int blockIndex, Instruction start, Instruction end) { if (start == null) throw new ArgumentNullException("start"); if (end == null) throw new ArgumentNullException("end"); this.BlockIndex = blockIndex; this.NodeType = ControlFlowNodeType.Normal; this.Start = start; this.End = end; this.Offset = start.Offset; }
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 (")"); }
void WriteStructureBody(ILStructure s, HashSet<int> branchTargets, ref Instruction inst, MemberMapping currentMethodMapping, int codeSize) { bool isFirstInstructionInStructure = true; bool prevInstructionWasBranch = false; int childIndex = 0; while (inst != null && inst.Offset < s.EndOffset) { int offset = inst.Offset; if (childIndex < s.Children.Count && s.Children[childIndex].StartOffset <= offset && offset < s.Children[childIndex].EndOffset) { ILStructure child = s.Children[childIndex++]; WriteStructureHeader(child); WriteStructureBody(child, branchTargets, ref inst, currentMethodMapping, codeSize); WriteStructureFooter(child); } else { if (!isFirstInstructionInStructure && (prevInstructionWasBranch || branchTargets.Contains(offset))) { output.WriteLine(); // put an empty line after branches, and in front of branch targets } inst.WriteTo(output); // add IL code mappings - used in debugger if (currentMethodMapping != null) { currentMethodMapping.MemberCodeMappings.Add( new SourceCodeMapping() { SourceCodeLine = output.CurrentLine, ILInstructionOffset = new ILRange { From = inst.Offset, To = inst.Next == null ? codeSize : inst.Next.Offset }, MemberMapping = currentMethodMapping }); } output.WriteLine(); prevInstructionWasBranch = inst.OpCode.FlowControl == FlowControl.Branch || inst.OpCode.FlowControl == FlowControl.Cond_Branch || inst.OpCode.FlowControl == FlowControl.Return || inst.OpCode.FlowControl == FlowControl.Throw; inst = inst.Next; } isFirstInstructionInStructure = false; } }
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 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); }
int GetTargetOffset (Instruction instruction) { if (instruction == null) { var last = body.instructions [body.instructions.Count - 1]; return last.offset + last.GetSize (); } return instruction.offset; }
static string FormatLabel (Instruction instruction) { return FormatLabel (instruction.Offset); }
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; }
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 / 3); 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 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; } }
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 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; } }
void ResolveBranches (Collection<Instruction> instructions) { var items = instructions.ToArray(); var size = instructions.Count; 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 bool IsFatRange (Instruction start, Instruction end) { if (end == null) return true; return end.Offset - start.Offset > 255 || start.Offset > 65535; }
public ILStructure(ILStructureType type, int startOffset, int endOffset, Instruction loopEntryPoint) { Debug.Assert(startOffset < endOffset); this.Type = type; this.StartOffset = startOffset; this.EndOffset = endOffset; this.LoopEntryPoint = loopEntryPoint; }