290 lines
9.2 KiB
C#
290 lines
9.2 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;
|
|
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);
|
|
}
|
|
}
|
|
} |