1 /* ****************************************************************************
3 * Copyright (c) Microsoft Corporation.
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.
11 * You must not remove this notice, or any other, from this software.
14 * ***************************************************************************/
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;
24 namespace Microsoft.Scripting.Interpreter {
25 internal abstract class EqualInstruction : 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;
31 public override int ConsumedStack { get { return 2; } }
32 public override int ProducedStack { get { return 1; } }
34 private EqualInstruction() {
37 public bool LiftedToNull { get; set; }
39 internal sealed class EqualBoolean : EqualInstruction {
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;
46 frame.Data[frame.StackIndex - 2] = (Boolean)l == (Boolean)r;
53 internal sealed class EqualSByte : EqualInstruction {
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;
60 frame.Data[frame.StackIndex - 2] = (SByte)l == (SByte)r;
67 internal sealed class EqualInt16 : EqualInstruction {
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;
74 frame.Data[frame.StackIndex - 2] = (Int16)l == (Int16)r;
81 internal sealed class EqualChar : EqualInstruction {
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;
88 frame.Data[frame.StackIndex - 2] = (Char)l == (Char)r;
95 internal sealed class EqualInt32 : EqualInstruction {
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;
102 frame.Data[frame.StackIndex - 2] = (Int32)l == (Int32)r;
108 internal sealed class EqualInt64 : EqualInstruction {
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;
115 frame.Data[frame.StackIndex - 2] = (Int64)l == (Int64)r;
122 internal sealed class EqualByte : EqualInstruction {
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;
129 frame.Data[frame.StackIndex - 2] = (Byte)l == (Byte)r;
136 internal sealed class EqualUInt16 : EqualInstruction {
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;
143 frame.Data[frame.StackIndex - 2] = (UInt16)l == (UInt16)r;
150 internal sealed class EqualUInt32 : EqualInstruction {
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;
157 frame.Data[frame.StackIndex - 2] = (UInt32)l == (UInt32)r;
164 internal sealed class EqualUInt64 : EqualInstruction {
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;
171 frame.Data[frame.StackIndex - 2] = (UInt64)l == (UInt64)r;
178 internal sealed class EqualSingle : EqualInstruction {
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;
185 frame.Data[frame.StackIndex - 2] = (Single)l == (Single)r;
192 internal sealed class EqualDouble : EqualInstruction {
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;
199 frame.Data[frame.StackIndex - 2] = (Double)l == (Double)r;
206 internal sealed class EqualReference : EqualInstruction {
207 public override int Run(InterpretedFrame frame) {
208 frame.Push(frame.Pop() == frame.Pop());
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 EqualBoolean());
218 case TypeCode.SByte: return _SByte ?? (_SByte = new EqualSByte());
219 case TypeCode.Byte: return _Byte ?? (_Byte = new EqualByte());
220 case TypeCode.Char: return _Char ?? (_Char = new EqualChar());
221 case TypeCode.Int16: return _Int16 ?? (_Int16 = new EqualInt16());
222 case TypeCode.Int32: return _Int32 ?? (_Int32 = new EqualInt32());
223 case TypeCode.Int64: return _Int64 ?? (_Int64 = new EqualInt64());
225 case TypeCode.UInt16: return _UInt16 ?? (_UInt16 = new EqualInt16());
226 case TypeCode.UInt32: return _UInt32 ?? (_UInt32 = new EqualInt32());
227 case TypeCode.UInt64: return _UInt64 ?? (_UInt64 = new EqualInt64());
229 case TypeCode.Single: return _Single ?? (_Single = new EqualSingle());
230 case TypeCode.Double: return _Double ?? (_Double = new EqualDouble());
232 case TypeCode.Object:
233 if (!type.IsValueType()) {
234 return _Reference ?? (_Reference = new EqualReference());
237 throw new NotImplementedException();
240 throw new NotImplementedException();
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 EqualBoolean() { LiftedToNull = true });
248 case TypeCode.SByte: return _SByteLifted ?? (_SByteLifted = new EqualSByte() { LiftedToNull = true });
249 case TypeCode.Byte: return _ByteLifted ?? (_ByteLifted = new EqualByte() { LiftedToNull = true });
250 case TypeCode.Char: return _CharLifted ?? (_CharLifted = new EqualChar() { LiftedToNull = true });
251 case TypeCode.Int16: return _Int16Lifted ?? (_Int16Lifted = new EqualInt16() { LiftedToNull = true });
252 case TypeCode.Int32: return _Int32Lifted ?? (_Int32Lifted = new EqualInt32() { LiftedToNull = true });
253 case TypeCode.Int64: return _Int64Lifted ?? (_Int64Lifted = new EqualInt64() { LiftedToNull = true });
255 case TypeCode.UInt16: return _UInt16Lifted ?? (_UInt16Lifted = new EqualInt16() { LiftedToNull = true });
256 case TypeCode.UInt32: return _UInt32Lifted ?? (_UInt32Lifted = new EqualInt32() { LiftedToNull = true });
257 case TypeCode.UInt64: return _UInt64Lifted ?? (_UInt64Lifted = new EqualInt64() { LiftedToNull = true });
259 case TypeCode.Single: return _SingleLifted ?? (_SingleLifted = new EqualSingle() { LiftedToNull = true });
260 case TypeCode.Double: return _DoubleLifted ?? (_DoubleLifted = new EqualDouble() { LiftedToNull = true });
263 throw Assert.Unreachable;
267 public override string ToString() {