Merge branch 'BigIntegerParse'
[mono.git] / mcs / class / dlr / Runtime / Microsoft.Dynamic / Interpreter / Instructions / NotEqualInstruction.cs
1 /* ****************************************************************************
2  *
3  * Copyright (c) Microsoft Corporation. 
4  *
5  * This source code is subject to terms and conditions of the Apache License, Version 2.0. A 
6  * copy of the license can be found in the License.html file at the root of this distribution. If 
7  * you cannot locate the  Apache License, Version 2.0, please send an email to 
8  * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
9  * by the terms of the Apache License, Version 2.0.
10  *
11  * You must not remove this notice, or any other, from this software.
12  *
13  *
14  * ***************************************************************************/
15
16 using System;
17 using System.Collections.Generic;
18 using System.Diagnostics;
19 using System.Reflection;
20 using System.Runtime.CompilerServices;
21 using Microsoft.Scripting.Runtime;
22 using Microsoft.Scripting.Utils;
23
24 namespace Microsoft.Scripting.Interpreter {
25     internal abstract class NotEqualInstruction : Instruction {
26         // Perf: EqualityComparer<T> but is 3/2 to 2 times slower.
27         private static Instruction _Reference, _Boolean, _SByte, _Int16, _Char, _Int32, _Int64, _Byte, _UInt16, _UInt32, _UInt64, _Single, _Double;
28         private static Instruction _BooleanLifted, _SByteLifted, _Int16Lifted, _CharLifted, _Int32Lifted, _Int64Lifted,
29             _ByteLifted, _UInt16Lifted, _UInt32Lifted, _UInt64Lifted, _SingleLifted, _DoubleLifted;
30
31         public override int ConsumedStack { get { return 2; } }
32         public override int ProducedStack { get { return 1; } }
33
34         private NotEqualInstruction() {
35         }
36
37         public bool LiftedToNull { get; set; }
38
39         internal sealed class NotEqualBoolean : NotEqualInstruction {
40             public override int Run(InterpretedFrame frame) {
41                 object l = frame.Data[frame.StackIndex - 2];
42                 object r = frame.Data[frame.StackIndex - 1];
43                 if (l == null || r == null)
44                     frame.Data[frame.StackIndex - 2] = LiftedToNull ? (object) null : (object) l != r;
45                 else
46                     frame.Data[frame.StackIndex - 2] = (Boolean)l != (Boolean)r;
47
48                 frame.StackIndex--;
49                 return +1;
50             }
51         }
52
53         internal sealed class NotEqualSByte : NotEqualInstruction {
54             public override int Run(InterpretedFrame frame) {
55                 object l = frame.Data[frame.StackIndex - 2];
56                 object r = frame.Data[frame.StackIndex - 1];
57                 if (l == null || r == null)
58                     frame.Data[frame.StackIndex - 2] = LiftedToNull ? (object) null : (object) l != r;
59                 else
60                     frame.Data[frame.StackIndex - 2] = (SByte)l != (SByte)r;
61
62                 frame.StackIndex--;
63                 return +1;
64             }
65         }
66
67         internal sealed class NotEqualInt16 : NotEqualInstruction {
68             public override int Run(InterpretedFrame frame) {
69                 object l = frame.Data[frame.StackIndex - 2];
70                 object r = frame.Data[frame.StackIndex - 1];
71                 if (l == null || r == null)
72                     frame.Data[frame.StackIndex - 2] = LiftedToNull ? (object) null : (object) l != r;
73                 else
74                     frame.Data[frame.StackIndex - 2] = (Int16)l != (Int16)r;
75
76                 frame.StackIndex--;
77                 return +1;
78             }
79         }
80
81         internal sealed class NotEqualChar : NotEqualInstruction {
82             public override int Run(InterpretedFrame frame) {
83                 object l = frame.Data[frame.StackIndex - 2];
84                 object r = frame.Data[frame.StackIndex - 1];
85                 if (l == null || r == null)
86                     frame.Data[frame.StackIndex - 2] = LiftedToNull ? (object) null : (object) l != r;
87                 else
88                     frame.Data[frame.StackIndex - 2] = (Char)l != (Char)r;
89
90                 frame.StackIndex--;
91                 return +1;
92             }
93         }
94
95         internal sealed class NotEqualInt32 : NotEqualInstruction {
96             public override int Run(InterpretedFrame frame) {
97                 object l = frame.Data[frame.StackIndex - 2];
98                 object r = frame.Data[frame.StackIndex - 1];
99                 if (l == null || r == null)
100                     frame.Data[frame.StackIndex - 2] = LiftedToNull ? (object) null : (object) l != r;
101                 else
102                     frame.Data[frame.StackIndex - 2] = (Int32)l != (Int32)r;
103
104                 frame.StackIndex--;
105                 return +1;            }
106         }
107
108         internal sealed class NotEqualInt64 : NotEqualInstruction {
109             public override int Run(InterpretedFrame frame) {
110                 object l = frame.Data[frame.StackIndex - 2];
111                 object r = frame.Data[frame.StackIndex - 1];
112                 if (l == null || r == null)
113                     frame.Data[frame.StackIndex - 2] = LiftedToNull ? (object) null : (object) l != r;
114                 else
115                     frame.Data[frame.StackIndex - 2] = (Int64)l != (Int64)r;
116
117                 frame.StackIndex--;
118                 return +1;
119             }
120         }
121
122         internal sealed class NotEqualByte : NotEqualInstruction {
123             public override int Run(InterpretedFrame frame) {
124                 object l = frame.Data[frame.StackIndex - 2];
125                 object r = frame.Data[frame.StackIndex - 1];
126                 if (l == null || r == null)
127                     frame.Data[frame.StackIndex - 2] = LiftedToNull ? (object) null : (object) l != r;
128                 else
129                     frame.Data[frame.StackIndex - 2] = (Byte)l != (Byte)r;
130
131                 frame.StackIndex--;
132                 return +1;
133             }
134         }
135
136         internal sealed class NotEqualUInt16 : NotEqualInstruction {
137             public override int Run(InterpretedFrame frame) {
138                 object l = frame.Data[frame.StackIndex - 2];
139                 object r = frame.Data[frame.StackIndex - 1];
140                 if (l == null || r == null)
141                     frame.Data[frame.StackIndex - 2] = LiftedToNull ? (object) null : (object) l != r;
142                 else
143                     frame.Data[frame.StackIndex - 2] = (UInt16)l != (UInt16)r;
144
145                 frame.StackIndex--;
146                 return +1;
147             }
148         }
149
150         internal sealed class NotEqualUInt32 : NotEqualInstruction {
151             public override int Run(InterpretedFrame frame) {
152                 object l = frame.Data[frame.StackIndex - 2];
153                 object r = frame.Data[frame.StackIndex - 1];
154                 if (l == null || r == null)
155                     frame.Data[frame.StackIndex - 2] = LiftedToNull ? (object) null : (object) l != r;
156                 else
157                     frame.Data[frame.StackIndex - 2] = (UInt32)l != (UInt32)r;
158
159                 frame.StackIndex--;
160                 return +1;
161             }
162         }
163
164         internal sealed class NotEqualUInt64 : NotEqualInstruction {
165             public override int Run(InterpretedFrame frame) {
166                 object l = frame.Data[frame.StackIndex - 2];
167                 object r = frame.Data[frame.StackIndex - 1];
168                 if (l == null || r == null)
169                     frame.Data[frame.StackIndex - 2] = LiftedToNull ? (object) null : (object) l != r;
170                 else
171                     frame.Data[frame.StackIndex - 2] = (UInt64)l != (UInt64)r;
172
173                 frame.StackIndex--;
174                 return +1;
175             }
176         }
177
178         internal sealed class NotEqualSingle : NotEqualInstruction {
179             public override int Run(InterpretedFrame frame) {
180                 object l = frame.Data[frame.StackIndex - 2];
181                 object r = frame.Data[frame.StackIndex - 1];
182                 if (l == null || r == null)
183                     frame.Data[frame.StackIndex - 2] = LiftedToNull ? (object) null : (object) l != r;
184                 else
185                     frame.Data[frame.StackIndex - 2] = (Single)l != (Single)r;
186
187                 frame.StackIndex--;
188                 return +1;
189             }
190         }
191
192         internal sealed class NotEqualDouble : NotEqualInstruction {
193             public override int Run(InterpretedFrame frame) {
194                 object l = frame.Data[frame.StackIndex - 2];
195                 object r = frame.Data[frame.StackIndex - 1];
196                 if (l == null || r == null)
197                     frame.Data[frame.StackIndex - 2] = LiftedToNull ? (object) null : (object) l != r;
198                 else
199                     frame.Data[frame.StackIndex - 2] = (Double)l != (Double)r;
200
201                 frame.StackIndex--;
202                 return +1;
203             }
204         }
205
206         internal sealed class NotEqualReference : NotEqualInstruction {
207             public override int Run(InterpretedFrame frame) {
208                 frame.Push(frame.Pop() != frame.Pop());
209                 return +1;
210             }
211         }
212
213         [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
214         public static Instruction Create(Type type) {
215             // Boxed enums can be unboxed as their underlying types:
216             switch ((type.IsEnum() ? Enum.GetUnderlyingType(type) : type).GetTypeCode()) {
217                 case TypeCode.Boolean: return _Boolean ?? (_Boolean = new NotEqualBoolean());
218                 case TypeCode.SByte: return _SByte ?? (_SByte = new NotEqualSByte());
219                 case TypeCode.Byte: return _Byte ?? (_Byte = new NotEqualByte());
220                 case TypeCode.Char: return _Char ?? (_Char = new NotEqualChar());
221                 case TypeCode.Int16: return _Int16 ?? (_Int16 = new NotEqualInt16());
222                 case TypeCode.Int32: return _Int32 ?? (_Int32 = new NotEqualInt32());
223                 case TypeCode.Int64: return _Int64 ?? (_Int64 = new NotEqualInt64());
224
225                 case TypeCode.UInt16: return _UInt16 ?? (_UInt16 = new NotEqualInt16());
226                 case TypeCode.UInt32: return _UInt32 ?? (_UInt32 = new NotEqualInt32());
227                 case TypeCode.UInt64: return _UInt64 ?? (_UInt64 = new NotEqualInt64());
228
229                 case TypeCode.Single: return _Single ?? (_Single = new NotEqualSingle());
230                 case TypeCode.Double: return _Double ?? (_Double = new NotEqualDouble());
231
232                 case TypeCode.Object:
233                     if (!type.IsValueType()) {
234                         return _Reference ?? (_Reference = new NotEqualReference());
235                     }
236                     // TODO: Nullable<T>
237                     throw new NotImplementedException();
238
239                 default:
240                     throw new NotImplementedException();
241             }
242         }
243
244         public static Instruction CreateLifted(Type type) {
245             // Boxed enums can be unboxed as their underlying types:
246             switch ((type.IsEnum() ? Enum.GetUnderlyingType(type) : type).GetTypeCode()) {
247                 case TypeCode.Boolean: return _BooleanLifted ?? (_BooleanLifted = new NotEqualBoolean() { LiftedToNull = true });
248                 case TypeCode.SByte: return _SByteLifted ?? (_SByteLifted = new NotEqualSByte() { LiftedToNull = true });
249                 case TypeCode.Byte: return _ByteLifted ?? (_ByteLifted = new NotEqualByte() { LiftedToNull = true });
250                 case TypeCode.Char: return _CharLifted ?? (_CharLifted = new NotEqualChar() { LiftedToNull = true });
251                 case TypeCode.Int16: return _Int16Lifted ?? (_Int16Lifted = new NotEqualInt16() { LiftedToNull = true });
252                 case TypeCode.Int32: return _Int32Lifted ?? (_Int32Lifted = new NotEqualInt32() { LiftedToNull = true });
253                 case TypeCode.Int64: return _Int64Lifted ?? (_Int64Lifted = new NotEqualInt64() { LiftedToNull = true });
254
255                 case TypeCode.UInt16: return _UInt16Lifted ?? (_UInt16Lifted = new NotEqualInt16() { LiftedToNull = true });
256                 case TypeCode.UInt32: return _UInt32Lifted ?? (_UInt32Lifted = new NotEqualInt32() { LiftedToNull = true });
257                 case TypeCode.UInt64: return _UInt64Lifted ?? (_UInt64Lifted = new NotEqualInt64() { LiftedToNull = true });
258
259                 case TypeCode.Single: return _SingleLifted ?? (_SingleLifted = new NotEqualSingle() { LiftedToNull = true });
260                 case TypeCode.Double: return _DoubleLifted ?? (_DoubleLifted = new NotEqualDouble() { LiftedToNull = true });
261
262                 default:
263                     throw Assert.Unreachable;
264             }
265         }
266
267         public override string ToString() {
268             return "NotEqual()";
269         }
270     }
271 }
272