2 Copyright (C) 2008, 2010 Jeroen Frijters
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.
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:
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.
25 using System.Diagnostics;
27 namespace IKVM.Reflection.Emit
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 = {
41 StackBehaviour.Pop1_pop1,
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
60 private static readonly StackBehaviour[] push = {
63 StackBehaviour.Push1_push1,
65 StackBehaviour.Pushi8,
66 StackBehaviour.Pushr4,
67 StackBehaviour.Pushr8,
68 StackBehaviour.Pushref,
69 StackBehaviour.Varpush
71 private readonly int value;
73 internal OpCode(int value)
78 public override bool Equals(object obj)
80 return this == obj as OpCode?;
83 public override int GetHashCode()
88 public bool Equals(OpCode other)
93 public static bool operator ==(OpCode a, OpCode b)
95 return a.value == b.value;
98 public static bool operator !=(OpCode a, OpCode b)
105 get { return (short)(value >> 22); }
110 get { return value < 0 ? 2 : 1; }
116 get { return OpCodes.GetName(this.Value); }
120 public OperandType OperandType
122 get { return (OperandType)((value & 0x3FFFFF) % OperandTypeCount); }
125 public FlowControl FlowControl
127 get { return (FlowControl)(((value & 0x3FFFFF) / OperandTypeCount) % FlowControlCount); }
130 internal int StackDiff
132 get { return ((((value & 0x3FFFFF) / (OperandTypeCount * FlowControlCount)) % StackDiffCount) - 3); }
135 public OpCodeType OpCodeType
137 get { return (OpCodeType)(((value & 0x3FFFFF) / (OperandTypeCount * FlowControlCount * StackDiffCount)) % OpCodeTypeCount); }
140 public StackBehaviour StackBehaviourPop
142 get { return pop[(((value & 0x3FFFFF) / (OperandTypeCount * FlowControlCount * StackDiffCount * OpCodeTypeCount)) % StackBehaviourPopCount)]; }
145 public StackBehaviour StackBehaviourPush
147 get { return push[(((value & 0x3FFFFF) / (OperandTypeCount * FlowControlCount * StackDiffCount * OpCodeTypeCount * StackBehaviourPopCount)) % StackBehaviourPushCount)]; }
151 static void Main(string[] args)
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))
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));
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))
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);
182 Console.WriteLine("\t\t\t}");
183 Console.WriteLine("\t\t\tthrow new ArgumentOutOfRangeException();");
184 Console.WriteLine("\t\t}");
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))
192 System.Reflection.Emit.OpCode opc1 = (System.Reflection.Emit.OpCode)field.GetValue(null);
193 if (System.Reflection.Emit.OpCodes.TakesSingleByteArgument(opc1))
195 Console.WriteLine("\t\t\t\tcase {0}:", opc1.Value);
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}");
205 private static void CheckEnumRange(System.Type type, int count)
207 foreach (var field in type.GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static))
209 int value = (int)field.GetValue(null);
210 Debug.Assert(value >= 0 && value < count);
214 static int Pack(System.Reflection.Emit.OpCode opcode)
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;
232 private static int Map(StackBehaviour[] array, System.Reflection.Emit.StackBehaviour stackBehaviour)
234 for (int i = 0; i < array.Length; i++)
236 if ((int)array[i] == (int)stackBehaviour)
241 throw new InvalidOperationException();
244 static int GetStackDiff(System.Reflection.Emit.StackBehaviour sb)
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:
253 case System.Reflection.Emit.StackBehaviour.Pop1:
254 case System.Reflection.Emit.StackBehaviour.Popi:
255 case System.Reflection.Emit.StackBehaviour.Popref:
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:
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:
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:
281 case System.Reflection.Emit.StackBehaviour.Push1_push1:
284 throw new InvalidOperationException();