do not check order sequence if option /order was not used
[mono.git] / mcs / class / IKVM.Reflection / Emit / OpCode.cs
1 /*
2   Copyright (C) 2008, 2010 Jeroen Frijters
3
4   This software is provided 'as-is', without any express or implied
5   warranty.  In no event will the authors be held liable for any damages
6   arising from the use of this software.
7
8   Permission is granted to anyone to use this software for any purpose,
9   including commercial applications, and to alter it and redistribute it
10   freely, subject to the following restrictions:
11
12   1. The origin of this software must not be misrepresented; you must not
13      claim that you wrote the original software. If you use this software
14      in a product, an acknowledgment in the product documentation would be
15      appreciated but is not required.
16   2. Altered source versions must be plainly marked as such, and must not be
17      misrepresented as being the original software.
18   3. This notice may not be removed or altered from any source distribution.
19
20   Jeroen Frijters
21   jeroen@frijters.net
22   
23 */
24 using System;
25 using System.Diagnostics;
26
27 namespace IKVM.Reflection.Emit
28 {
29         public struct OpCode
30         {
31                 private const int ValueCount = 1024;
32                 private const int OperandTypeCount = 19;
33                 private const int FlowControlCount = 9;
34                 private const int StackDiffCount = 5;
35                 private const int OpCodeTypeCount = 6;
36                 private const int StackBehaviourPopCount = 20;
37                 private const int StackBehaviourPushCount = 9;
38                 private static readonly StackBehaviour[] pop = {
39                         StackBehaviour.Pop0,
40                         StackBehaviour.Pop1,
41                         StackBehaviour.Pop1_pop1,
42                         StackBehaviour.Popi,
43                         StackBehaviour.Popi_pop1,
44                         StackBehaviour.Popi_popi,
45                         StackBehaviour.Popi_popi8,
46                         StackBehaviour.Popi_popi_popi,
47                         StackBehaviour.Popi_popr4,
48                         StackBehaviour.Popi_popr8,
49                         StackBehaviour.Popref,
50                         StackBehaviour.Popref_pop1,
51                         StackBehaviour.Popref_popi,
52                         StackBehaviour.Popref_popi_popi,
53                         StackBehaviour.Popref_popi_popi8,
54                         StackBehaviour.Popref_popi_popr4,
55                         StackBehaviour.Popref_popi_popr8,
56                         StackBehaviour.Popref_popi_popref,
57                         StackBehaviour.Varpop,
58                         StackBehaviour.Popref_popi_pop1
59                 };
60                 private static readonly StackBehaviour[] push = {
61                         StackBehaviour.Push0,
62                         StackBehaviour.Push1,
63                         StackBehaviour.Push1_push1,
64                         StackBehaviour.Pushi,
65                         StackBehaviour.Pushi8,
66                         StackBehaviour.Pushr4,
67                         StackBehaviour.Pushr8,
68                         StackBehaviour.Pushref,
69                         StackBehaviour.Varpush
70                 };
71                 private readonly int value;
72
73                 internal OpCode(int value)
74                 {
75                         this.value = value;
76                 }
77
78                 public override bool Equals(object obj)
79                 {
80                         return this == obj as OpCode?;
81                 }
82
83                 public override int GetHashCode()
84                 {
85                         return value;
86                 }
87
88                 public bool Equals(OpCode other)
89                 {
90                         return this == other;
91                 }
92
93                 public static bool operator ==(OpCode a, OpCode b)
94                 {
95                         return a.value == b.value;
96                 }
97
98                 public static bool operator !=(OpCode a, OpCode b)
99                 {
100                         return !(a == b);
101                 }
102
103                 public short Value
104                 {
105                         get { return (short)(value >> 22); }
106                 }
107
108                 public int Size
109                 {
110                         get { return value < 0 ? 2 : 1; }
111                 }
112
113 #if !GENERATOR
114                 public string Name
115                 {
116                         get { return OpCodes.GetName(this.Value); }
117                 }
118 #endif
119
120                 public OperandType OperandType
121                 {
122                         get { return (OperandType)((value & 0x3FFFFF) % OperandTypeCount); }
123                 }
124
125                 public FlowControl FlowControl
126                 {
127                         get { return (FlowControl)(((value & 0x3FFFFF) / OperandTypeCount) % FlowControlCount); }
128                 }
129
130                 internal int StackDiff
131                 {
132                         get { return ((((value & 0x3FFFFF) / (OperandTypeCount * FlowControlCount)) % StackDiffCount) - 3); }
133                 }
134
135                 public OpCodeType OpCodeType
136                 {
137                         get { return (OpCodeType)(((value & 0x3FFFFF) / (OperandTypeCount * FlowControlCount * StackDiffCount)) % OpCodeTypeCount); }
138                 }
139
140                 public StackBehaviour StackBehaviourPop
141                 {
142                         get { return pop[(((value & 0x3FFFFF) / (OperandTypeCount * FlowControlCount * StackDiffCount * OpCodeTypeCount)) % StackBehaviourPopCount)]; }
143                 }
144
145                 public StackBehaviour StackBehaviourPush
146                 {
147                         get { return push[(((value & 0x3FFFFF) / (OperandTypeCount * FlowControlCount * StackDiffCount * OpCodeTypeCount * StackBehaviourPopCount)) % StackBehaviourPushCount)]; }
148                 }
149
150 #if GENERATOR
151                 static void Main(string[] args)
152                 {
153                         Debug.Assert(pop.Length == StackBehaviourPopCount);
154                         Debug.Assert(push.Length == StackBehaviourPushCount);
155                         CheckEnumRange(typeof(FlowControl), FlowControlCount);
156                         CheckEnumRange(typeof(OpCodeType), OpCodeTypeCount);
157                         CheckEnumRange(typeof(OperandType), OperandTypeCount);
158                         foreach (var field in typeof(System.Reflection.Emit.OpCodes).GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static))
159                         {
160                                 System.Reflection.Emit.OpCode opc1 = (System.Reflection.Emit.OpCode)field.GetValue(null);
161                                 IKVM.Reflection.Emit.OpCode opc2 = new IKVM.Reflection.Emit.OpCode(Pack(opc1));
162                                 Debug.Assert(opc1.Value == opc2.Value);
163                                 Debug.Assert(opc1.Size == opc2.Size);
164                                 Debug.Assert((int)opc1.FlowControl == (int)opc2.FlowControl);
165                                 Debug.Assert((int)opc1.OpCodeType == (int)opc2.OpCodeType);
166                                 Debug.Assert((int)opc1.OperandType == (int)opc2.OperandType);
167                                 Debug.Assert((int)opc1.StackBehaviourPop == (int)opc2.StackBehaviourPop);
168                                 Debug.Assert((int)opc1.StackBehaviourPush == (int)opc2.StackBehaviourPush);
169                                 Console.WriteLine("\t\tpublic static readonly OpCode {0} = new OpCode({1});", field.Name, Pack(opc1));
170                         }
171                         Console.WriteLine();
172                         Console.WriteLine("\t\tinternal static string GetName(int value)");
173                         Console.WriteLine("\t\t{");
174                         Console.WriteLine("\t\t\tswitch (value)");
175                         Console.WriteLine("\t\t\t{");
176                         foreach (var field in typeof(System.Reflection.Emit.OpCodes).GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static))
177                         {
178                                 System.Reflection.Emit.OpCode opc1 = (System.Reflection.Emit.OpCode)field.GetValue(null);
179                                 Console.WriteLine("\t\t\t\tcase {0}:", opc1.Value);
180                                 Console.WriteLine("\t\t\t\t\treturn \"{0}\";", opc1.Name);
181                         }
182                         Console.WriteLine("\t\t\t}");
183                         Console.WriteLine("\t\t\tthrow new ArgumentOutOfRangeException();");
184                         Console.WriteLine("\t\t}");
185                         Console.WriteLine();
186                         Console.WriteLine("\t\tpublic static bool TakesSingleByteArgument(OpCode inst)");
187                         Console.WriteLine("\t\t{");
188                         Console.WriteLine("\t\t\tswitch (inst.Value)");
189                         Console.WriteLine("\t\t\t{");
190                         foreach (var field in typeof(System.Reflection.Emit.OpCodes).GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static))
191                         {
192                                 System.Reflection.Emit.OpCode opc1 = (System.Reflection.Emit.OpCode)field.GetValue(null);
193                                 if (System.Reflection.Emit.OpCodes.TakesSingleByteArgument(opc1))
194                                 {
195                                         Console.WriteLine("\t\t\t\tcase {0}:", opc1.Value);
196                                 }
197                         }
198                         Console.WriteLine("\t\t\t\t\treturn true;");
199                         Console.WriteLine("\t\t\t\tdefault:");
200                         Console.WriteLine("\t\t\t\t\treturn false;");
201                         Console.WriteLine("\t\t\t}");
202                         Console.WriteLine("\t\t}");
203                 }
204
205                 private static void CheckEnumRange(System.Type type, int count)
206                 {
207                         foreach (var field in type.GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static))
208                         {
209                                 int value = (int)field.GetValue(null);
210                                 Debug.Assert(value >= 0 && value < count);
211                         }
212                 }
213
214                 static int Pack(System.Reflection.Emit.OpCode opcode)
215                 {
216                         int value = 0;
217                         value *= StackBehaviourPushCount;
218                         value += Map(push, opcode.StackBehaviourPush);
219                         value *= StackBehaviourPopCount;
220                         value += Map(pop, opcode.StackBehaviourPop);
221                         value *= OpCodeTypeCount;
222                         value += (int)opcode.OpCodeType;
223                         value *= StackDiffCount;
224                         value += 3 + GetStackDiff(opcode.StackBehaviourPush) + GetStackDiff(opcode.StackBehaviourPop);
225                         value *= FlowControlCount;
226                         value += (int)opcode.FlowControl;
227                         value *= OperandTypeCount;
228                         value += (int)opcode.OperandType;
229                         return (opcode.Value << 22) | value;
230                 }
231
232                 private static int Map(StackBehaviour[] array, System.Reflection.Emit.StackBehaviour stackBehaviour)
233                 {
234                         for (int i = 0; i < array.Length; i++)
235                         {
236                                 if ((int)array[i] == (int)stackBehaviour)
237                                 {
238                                         return i;
239                                 }
240                         }
241                         throw new InvalidOperationException();
242                 }
243
244                 static int GetStackDiff(System.Reflection.Emit.StackBehaviour sb)
245                 {
246                         switch (sb)
247                         {
248                                 case System.Reflection.Emit.StackBehaviour.Pop0:
249                                 case System.Reflection.Emit.StackBehaviour.Push0:
250                                 case System.Reflection.Emit.StackBehaviour.Varpop:
251                                 case System.Reflection.Emit.StackBehaviour.Varpush:
252                                         return 0;
253                                 case System.Reflection.Emit.StackBehaviour.Pop1:
254                                 case System.Reflection.Emit.StackBehaviour.Popi:
255                                 case System.Reflection.Emit.StackBehaviour.Popref:
256                                         return -1;
257                                 case System.Reflection.Emit.StackBehaviour.Pop1_pop1:
258                                 case System.Reflection.Emit.StackBehaviour.Popi_pop1:
259                                 case System.Reflection.Emit.StackBehaviour.Popi_popi:
260                                 case System.Reflection.Emit.StackBehaviour.Popi_popi8:
261                                 case System.Reflection.Emit.StackBehaviour.Popi_popr4:
262                                 case System.Reflection.Emit.StackBehaviour.Popi_popr8:
263                                 case System.Reflection.Emit.StackBehaviour.Popref_pop1:
264                                 case System.Reflection.Emit.StackBehaviour.Popref_popi:
265                                         return -2;
266                                 case System.Reflection.Emit.StackBehaviour.Popi_popi_popi:
267                                 case System.Reflection.Emit.StackBehaviour.Popref_popi_pop1:
268                                 case System.Reflection.Emit.StackBehaviour.Popref_popi_popi:
269                                 case System.Reflection.Emit.StackBehaviour.Popref_popi_popi8:
270                                 case System.Reflection.Emit.StackBehaviour.Popref_popi_popr4:
271                                 case System.Reflection.Emit.StackBehaviour.Popref_popi_popr8:
272                                 case System.Reflection.Emit.StackBehaviour.Popref_popi_popref:
273                                         return -3;
274                                 case System.Reflection.Emit.StackBehaviour.Push1:
275                                 case System.Reflection.Emit.StackBehaviour.Pushi:
276                                 case System.Reflection.Emit.StackBehaviour.Pushi8:
277                                 case System.Reflection.Emit.StackBehaviour.Pushr4:
278                                 case System.Reflection.Emit.StackBehaviour.Pushr8:
279                                 case System.Reflection.Emit.StackBehaviour.Pushref:
280                                         return 1;
281                                 case System.Reflection.Emit.StackBehaviour.Push1_push1:
282                                         return 2;
283                         }
284                         throw new InvalidOperationException();
285                 }
286 #endif // GENERATOR
287         }
288 }