// // Author: // Jb Evain (jbevain@gmail.com) // // Copyright (c) 2008 - 2015 Jb Evain // Copyright (c) 2008 - 2011 Novell, Inc. // // Licensed under the MIT/X11 license. // using System; using System.Text; namespace MonoFN.Cecil.Cil { public sealed class Instruction { internal int offset; internal OpCode opcode; internal object operand; internal Instruction previous; internal Instruction next; public int Offset { get { return offset; } set { offset = value; } } public OpCode OpCode { get { return opcode; } set { opcode = value; } } public object Operand { get { return operand; } set { operand = value; } } public Instruction Previous { get { return previous; } set { previous = value; } } public Instruction Next { get { return next; } set { next = value; } } internal Instruction(int offset, OpCode opCode) { this.offset = offset; opcode = opCode; } internal Instruction(OpCode opcode, object operand) { this.opcode = opcode; this.operand = operand; } public int GetSize() { int size = opcode.Size; switch (opcode.OperandType) { case OperandType.InlineSwitch: return size + (1 + ((Instruction[])operand).Length) * 4; case OperandType.InlineI8: case OperandType.InlineR: return size + 8; case OperandType.InlineBrTarget: case OperandType.InlineField: case OperandType.InlineI: case OperandType.InlineMethod: case OperandType.InlineString: case OperandType.InlineTok: case OperandType.InlineType: case OperandType.ShortInlineR: case OperandType.InlineSig: return size + 4; case OperandType.InlineArg: case OperandType.InlineVar: return size + 2; case OperandType.ShortInlineBrTarget: case OperandType.ShortInlineI: case OperandType.ShortInlineArg: case OperandType.ShortInlineVar: return size + 1; default: return size; } } public override string ToString() { StringBuilder instruction = new(); AppendLabel(instruction, this); instruction.Append(':'); instruction.Append(' '); instruction.Append(opcode.Name); if (operand == null) return instruction.ToString(); instruction.Append(' '); switch (opcode.OperandType) { case OperandType.ShortInlineBrTarget: case OperandType.InlineBrTarget: AppendLabel(instruction, (Instruction)operand); break; case OperandType.InlineSwitch: Instruction[] labels = (Instruction[])operand; for (int i = 0; i < labels.Length; i++) { if (i > 0) instruction.Append(','); AppendLabel(instruction, labels[i]); } break; case OperandType.InlineString: instruction.Append('\"'); instruction.Append(operand); instruction.Append('\"'); break; default: instruction.Append(operand); break; } return instruction.ToString(); } private static void AppendLabel(StringBuilder builder, Instruction instruction) { builder.Append("IL_"); builder.Append(instruction.offset.ToString("x4")); } public static Instruction Create(OpCode opcode) { if (opcode.OperandType != OperandType.InlineNone) throw new ArgumentException("opcode"); return new(opcode, null); } public static Instruction Create(OpCode opcode, TypeReference type) { if (type == null) throw new ArgumentNullException("type"); if (opcode.OperandType != OperandType.InlineType && opcode.OperandType != OperandType.InlineTok) throw new ArgumentException("opcode"); return new(opcode, type); } public static Instruction Create(OpCode opcode, CallSite site) { if (site == null) throw new ArgumentNullException("site"); if (opcode.Code != Code.Calli) throw new ArgumentException("code"); return new(opcode, site); } public static Instruction Create(OpCode opcode, MethodReference method) { if (method == null) throw new ArgumentNullException("method"); if (opcode.OperandType != OperandType.InlineMethod && opcode.OperandType != OperandType.InlineTok) throw new ArgumentException("opcode"); return new(opcode, method); } public static Instruction Create(OpCode opcode, FieldReference field) { if (field == null) throw new ArgumentNullException("field"); if (opcode.OperandType != OperandType.InlineField && opcode.OperandType != OperandType.InlineTok) throw new ArgumentException("opcode"); return new(opcode, field); } public static Instruction Create(OpCode opcode, string value) { if (value == null) throw new ArgumentNullException("value"); if (opcode.OperandType != OperandType.InlineString) throw new ArgumentException("opcode"); return new(opcode, value); } public static Instruction Create(OpCode opcode, sbyte value) { if (opcode.OperandType != OperandType.ShortInlineI && opcode != OpCodes.Ldc_I4_S) throw new ArgumentException("opcode"); return new(opcode, value); } public static Instruction Create(OpCode opcode, byte value) { if (opcode.OperandType != OperandType.ShortInlineI || opcode == OpCodes.Ldc_I4_S) throw new ArgumentException("opcode"); return new(opcode, value); } public static Instruction Create(OpCode opcode, int value) { if (opcode.OperandType != OperandType.InlineI) throw new ArgumentException("opcode"); return new(opcode, value); } public static Instruction Create(OpCode opcode, long value) { if (opcode.OperandType != OperandType.InlineI8) throw new ArgumentException("opcode"); return new(opcode, value); } public static Instruction Create(OpCode opcode, float value) { if (opcode.OperandType != OperandType.ShortInlineR) throw new ArgumentException("opcode"); return new(opcode, value); } public static Instruction Create(OpCode opcode, double value) { if (opcode.OperandType != OperandType.InlineR) throw new ArgumentException("opcode"); return new(opcode, value); } 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(opcode, target); } 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(opcode, targets); } public static Instruction Create(OpCode opcode, VariableDefinition variable) { if (variable == null) throw new ArgumentNullException("variable"); if (opcode.OperandType != OperandType.ShortInlineVar && opcode.OperandType != OperandType.InlineVar) throw new ArgumentException("opcode"); return new(opcode, variable); } public static Instruction Create(OpCode opcode, ParameterDefinition parameter) { if (parameter == null) throw new ArgumentNullException("parameter"); if (opcode.OperandType != OperandType.ShortInlineArg && opcode.OperandType != OperandType.InlineArg) throw new ArgumentException("opcode"); return new(opcode, parameter); } } }