297 lines
7.4 KiB
C#
297 lines
7.4 KiB
C#
//
|
|
// 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;
|
|
this.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 ()
|
|
{
|
|
var instruction = new StringBuilder ();
|
|
|
|
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:
|
|
var 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 ();
|
|
}
|
|
|
|
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 Instruction (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 Instruction (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 Instruction (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 Instruction (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 Instruction (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 Instruction (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 Instruction (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 Instruction (opcode, value);
|
|
}
|
|
|
|
public static Instruction Create (OpCode opcode, int value)
|
|
{
|
|
if (opcode.OperandType != OperandType.InlineI)
|
|
throw new ArgumentException ("opcode");
|
|
|
|
return new Instruction (opcode, value);
|
|
}
|
|
|
|
public static Instruction Create (OpCode opcode, long value)
|
|
{
|
|
if (opcode.OperandType != OperandType.InlineI8)
|
|
throw new ArgumentException ("opcode");
|
|
|
|
return new Instruction (opcode, value);
|
|
}
|
|
|
|
public static Instruction Create (OpCode opcode, float value)
|
|
{
|
|
if (opcode.OperandType != OperandType.ShortInlineR)
|
|
throw new ArgumentException ("opcode");
|
|
|
|
return new Instruction (opcode, value);
|
|
}
|
|
|
|
public static Instruction Create (OpCode opcode, double value)
|
|
{
|
|
if (opcode.OperandType != OperandType.InlineR)
|
|
throw new ArgumentException ("opcode");
|
|
|
|
return new Instruction (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 Instruction (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 Instruction (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 Instruction (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 Instruction (opcode, parameter);
|
|
}
|
|
}
|
|
}
|