|
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
// <OWNER>Microsoft</OWNER>
namespace System.Reflection.Emit {
using System;
using System.Threading;
using System.Security.Permissions;
using System.Diagnostics.Contracts;
[System.Runtime.InteropServices.ComVisible(true)]
public struct OpCode
{
//
// Use packed bitfield for flags to avoid code bloat
//
internal const int OperandTypeMask = 0x1F; // 000000000000000000000000000XXXXX
internal const int FlowControlShift = 5; // 00000000000000000000000XXXX00000
internal const int FlowControlMask = 0x0F;
internal const int OpCodeTypeShift = 9; // 00000000000000000000XXX000000000
internal const int OpCodeTypeMask = 0x07;
internal const int StackBehaviourPopShift = 12; // 000000000000000XXXXX000000000000
internal const int StackBehaviourPushShift = 17; // 0000000000XXXXX00000000000000000
internal const int StackBehaviourMask = 0x1F;
internal const int SizeShift = 22; // 00000000XX0000000000000000000000
internal const int SizeMask = 0x03;
internal const int EndsUncondJmpBlkFlag = 0x01000000; // 0000000X000000000000000000000000
// unused // 0000XXX0000000000000000000000000
internal const int StackChangeShift = 28; // XXXX0000000000000000000000000000
#if FEATURE_CORECLR
private OpCodeValues m_value;
private int m_flags;
internal OpCode(OpCodeValues value, int flags)
{
m_value = value;
m_flags = flags;
}
internal bool EndsUncondJmpBlk()
{
return (m_flags & EndsUncondJmpBlkFlag) != 0;
}
internal int StackChange()
{
return (m_flags >> StackChangeShift);
}
public OperandType OperandType
{
get
{
return (OperandType)(m_flags & OperandTypeMask);
}
}
public FlowControl FlowControl
{
get
{
return (FlowControl)((m_flags >> FlowControlShift) & FlowControlMask);
}
}
public OpCodeType OpCodeType
{
get
{
return (OpCodeType)((m_flags >> OpCodeTypeShift) & OpCodeTypeMask);
}
}
public StackBehaviour StackBehaviourPop
{
get
{
return (StackBehaviour)((m_flags >> StackBehaviourPopShift) & StackBehaviourMask);
}
}
public StackBehaviour StackBehaviourPush
{
get
{
return (StackBehaviour)((m_flags >> StackBehaviourPushShift) & StackBehaviourMask);
}
}
public int Size
{
get
{
return (m_flags >> SizeShift) & SizeMask;
}
}
public short Value
{
get
{
return (short)m_value;
}
}
#else // FEATURE_CORECLR
//
// The exact layout is part of the legacy COM mscorlib surface, so it is
// pretty much set in stone for desktop CLR. Ideally, we would use the packed
// bit field like for CoreCLR, but that would be a breaking change.
//
// disable csharp compiler warning #0414: field assigned unused value
#pragma warning disable 0414
private String m_stringname; // not used - computed lazily
#pragma warning restore 0414
private StackBehaviour m_pop;
private StackBehaviour m_push;
private OperandType m_operand;
private OpCodeType m_type;
private int m_size;
private byte m_s1;
private byte m_s2;
private FlowControl m_ctrl;
// Specifies whether the current instructions causes the control flow to
// change unconditionally.
private bool m_endsUncondJmpBlk;
// Specifies the stack change that the current instruction causes not
// taking into account the operand dependant stack changes.
private int m_stackChange;
internal OpCode(OpCodeValues value, int flags)
{
m_stringname = null; // computed lazily
m_pop = (StackBehaviour)((flags >> StackBehaviourPopShift) & StackBehaviourMask);
m_push = (StackBehaviour)((flags >> StackBehaviourPushShift) & StackBehaviourMask);
m_operand = (OperandType)(flags & OperandTypeMask);
m_type = (OpCodeType)((flags >> OpCodeTypeShift) & OpCodeTypeMask);
m_size = (flags >> SizeShift) & SizeMask;
m_s1 = (byte)((int)value >> 8);
m_s2 = (byte)(int)value;
m_ctrl = (FlowControl)((flags >> FlowControlShift) & FlowControlMask);
m_endsUncondJmpBlk = (flags & EndsUncondJmpBlkFlag) != 0;
m_stackChange = (flags >> StackChangeShift);
}
internal bool EndsUncondJmpBlk()
{
return m_endsUncondJmpBlk;
}
internal int StackChange()
{
return m_stackChange;
}
public OperandType OperandType
{
get
{
return (m_operand);
}
}
public FlowControl FlowControl
{
get
{
return (m_ctrl);
}
}
public OpCodeType OpCodeType
{
get
{
return (m_type);
}
}
public StackBehaviour StackBehaviourPop
{
get
{
return (m_pop);
}
}
public StackBehaviour StackBehaviourPush
{
get
{
return (m_push);
}
}
public int Size
{
get
{
return (m_size);
}
}
public short Value
{
get
{
if (m_size == 2)
return (short)(m_s1 << 8 | m_s2);
return (short)m_s2;
}
}
#endif // FEATURE_CORECLR
private static volatile string[] g_nameCache;
public String Name
{
get
{
if (Size == 0)
return null;
// Create and cache the opcode names lazily. They should be rarely used (only for logging, etc.)
// Note that we do not any locks here because of we always get the same names. The last one wins.
string[] nameCache = g_nameCache;
if (nameCache == null) {
nameCache = new String[0x11f];
g_nameCache = nameCache;
}
OpCodeValues opCodeValue = (OpCodeValues)(ushort)Value;
int idx = (int)opCodeValue;
if (idx > 0xFF) {
if (idx >= 0xfe00 && idx <= 0xfe1e) {
// Transform two byte opcode value to lower range that's suitable
// for array index
idx = 0x100 + (idx - 0xfe00);
}
else {
// Unknown opcode
return null;
}
}
String name = Volatile.Read(ref nameCache[idx]);
if (name != null)
return name;
// Create ilasm style name from the enum value name.
name = Enum.GetName(typeof(OpCodeValues), opCodeValue).ToLowerInvariant().Replace("_", ".");
Volatile.Write(ref nameCache[idx], name);
return name;
}
}
[Pure]
public override bool Equals(Object obj)
{
if (obj is OpCode)
return Equals((OpCode)obj);
else
return false;
}
[Pure]
public bool Equals(OpCode obj)
{
return obj.Value == Value;
}
[Pure]
public static bool operator ==(OpCode a, OpCode b)
{
return a.Equals(b);
}
[Pure]
public static bool operator !=(OpCode a, OpCode b)
{
return !(a == b);
}
public override int GetHashCode()
{
return Value;
}
public override String ToString()
{
return Name;
}
}
}
|