|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Diagnostics;
using System.Dynamic.Utils;
namespace System.Linq.Expressions.Interpreter
{
internal abstract class EqualInstruction : Instruction
{
// Perf: EqualityComparer<T> but is 3/2 to 2 times slower.
private static Instruction? s_reference, s_Boolean, s_SByte, s_Int16, s_Char, s_Int32, s_Int64, s_Byte, s_UInt16, s_UInt32, s_UInt64, s_Single, s_Double;
private static Instruction? s_BooleanLiftedToNull, s_SByteLiftedToNull, s_Int16LiftedToNull, s_CharLiftedToNull, s_Int32LiftedToNull, s_Int64LiftedToNull, s_ByteLiftedToNull, s_UInt16LiftedToNull, s_UInt32LiftedToNull, s_UInt64LiftedToNull, s_SingleLiftedToNull, s_DoubleLiftedToNull;
public override int ConsumedStack => 2;
public override int ProducedStack => 1;
public override string InstructionName => "Equal";
private EqualInstruction() { }
private sealed class EqualBoolean : EqualInstruction
{
public override int Run(InterpretedFrame frame)
{
object? right = frame.Pop();
object? left = frame.Pop();
if (left == null)
{
frame.Push(right == null);
}
else if (right == null)
{
frame.Push(false);
}
else
{
frame.Push((bool)left == (bool)right);
}
return 1;
}
}
private sealed class EqualSByte : EqualInstruction
{
public override int Run(InterpretedFrame frame)
{
object? right = frame.Pop();
object? left = frame.Pop();
if (left == null)
{
frame.Push(right == null);
}
else if (right == null)
{
frame.Push(false);
}
else
{
frame.Push((sbyte)left == (sbyte)right);
}
return 1;
}
}
private sealed class EqualInt16 : EqualInstruction
{
public override int Run(InterpretedFrame frame)
{
object? right = frame.Pop();
object? left = frame.Pop();
if (left == null)
{
frame.Push(right == null);
}
else if (right == null)
{
frame.Push(false);
}
else
{
frame.Push((short)left == (short)right);
}
return 1;
}
}
private sealed class EqualChar : EqualInstruction
{
public override int Run(InterpretedFrame frame)
{
object? right = frame.Pop();
object? left = frame.Pop();
if (left == null)
{
frame.Push(right == null);
}
else if (right == null)
{
frame.Push(false);
}
else
{
frame.Push((char)left == (char)right);
}
return 1;
}
}
private sealed class EqualInt32 : EqualInstruction
{
public override int Run(InterpretedFrame frame)
{
object? right = frame.Pop();
object? left = frame.Pop();
if (left == null)
{
frame.Push(right == null);
}
else if (right == null)
{
frame.Push(false);
}
else
{
frame.Push((int)left == (int)right);
}
return 1;
}
}
private sealed class EqualInt64 : EqualInstruction
{
public override int Run(InterpretedFrame frame)
{
object? right = frame.Pop();
object? left = frame.Pop();
if (left == null)
{
frame.Push(right == null);
}
else if (right == null)
{
frame.Push(false);
}
else
{
frame.Push((long)left == (long)right);
}
return 1;
}
}
private sealed class EqualByte : EqualInstruction
{
public override int Run(InterpretedFrame frame)
{
object? right = frame.Pop();
object? left = frame.Pop();
if (left == null)
{
frame.Push(right == null);
}
else if (right == null)
{
frame.Push(false);
}
else
{
frame.Push((byte)left == (byte)right);
}
return 1;
}
}
private sealed class EqualUInt16 : EqualInstruction
{
public override int Run(InterpretedFrame frame)
{
object? right = frame.Pop();
object? left = frame.Pop();
if (left == null)
{
frame.Push(right == null);
}
else if (right == null)
{
frame.Push(false);
}
else
{
frame.Push((ushort)left == (ushort)right);
}
return 1;
}
}
private sealed class EqualUInt32 : EqualInstruction
{
public override int Run(InterpretedFrame frame)
{
object? right = frame.Pop();
object? left = frame.Pop();
if (left == null)
{
frame.Push(right == null);
}
else if (right == null)
{
frame.Push(false);
}
else
{
frame.Push((uint)left == (uint)right);
}
return 1;
}
}
private sealed class EqualUInt64 : EqualInstruction
{
public override int Run(InterpretedFrame frame)
{
object? right = frame.Pop();
object? left = frame.Pop();
if (left == null)
{
frame.Push(right == null);
}
else if (right == null)
{
frame.Push(false);
}
else
{
frame.Push((ulong)left == (ulong)right);
}
return 1;
}
}
private sealed class EqualSingle : EqualInstruction
{
public override int Run(InterpretedFrame frame)
{
object? right = frame.Pop();
object? left = frame.Pop();
if (left == null)
{
frame.Push(right == null);
}
else if (right == null)
{
frame.Push(false);
}
else
{
frame.Push((float)left == (float)right);
}
return 1;
}
}
private sealed class EqualDouble : EqualInstruction
{
public override int Run(InterpretedFrame frame)
{
object? right = frame.Pop();
object? left = frame.Pop();
if (left == null)
{
frame.Push(right == null);
}
else if (right == null)
{
frame.Push(false);
}
else
{
frame.Push((double)left == (double)right);
}
return 1;
}
}
private sealed class EqualReference : EqualInstruction
{
public override int Run(InterpretedFrame frame)
{
frame.Push(frame.Pop() == frame.Pop());
return 1;
}
}
private sealed class EqualBooleanLiftedToNull : EqualInstruction
{
public override int Run(InterpretedFrame frame)
{
object? right = frame.Pop();
object? left = frame.Pop();
if (left == null || right == null)
{
frame.Push(null);
}
else
{
frame.Push((bool)left == (bool)right);
}
return 1;
}
}
private sealed class EqualSByteLiftedToNull : EqualInstruction
{
public override int Run(InterpretedFrame frame)
{
object? right = frame.Pop();
object? left = frame.Pop();
if (left == null || right == null)
{
frame.Push(null);
}
else
{
frame.Push((sbyte)left == (sbyte)right);
}
return 1;
}
}
private sealed class EqualInt16LiftedToNull : EqualInstruction
{
public override int Run(InterpretedFrame frame)
{
object? right = frame.Pop();
object? left = frame.Pop();
if (left == null || right == null)
{
frame.Push(null);
}
else
{
frame.Push((short)left == (short)right);
}
return 1;
}
}
private sealed class EqualCharLiftedToNull : EqualInstruction
{
public override int Run(InterpretedFrame frame)
{
object? right = frame.Pop();
object? left = frame.Pop();
if (left == null || right == null)
{
frame.Push(null);
}
else
{
frame.Push((char)left == (char)right);
}
return 1;
}
}
private sealed class EqualInt32LiftedToNull : EqualInstruction
{
public override int Run(InterpretedFrame frame)
{
object? right = frame.Pop();
object? left = frame.Pop();
if (left == null || right == null)
{
frame.Push(null);
}
else
{
frame.Push((int)left == (int)right);
}
return 1;
}
}
private sealed class EqualInt64LiftedToNull : EqualInstruction
{
public override int Run(InterpretedFrame frame)
{
object? right = frame.Pop();
object? left = frame.Pop();
if (left == null || right == null)
{
frame.Push(null);
}
else
{
frame.Push((long)left == (long)right);
}
return 1;
}
}
private sealed class EqualByteLiftedToNull : EqualInstruction
{
public override int Run(InterpretedFrame frame)
{
object? right = frame.Pop();
object? left = frame.Pop();
if (left == null || right == null)
{
frame.Push(null);
}
else
{
frame.Push((byte)left == (byte)right);
}
return 1;
}
}
private sealed class EqualUInt16LiftedToNull : EqualInstruction
{
public override int Run(InterpretedFrame frame)
{
object? right = frame.Pop();
object? left = frame.Pop();
if (left == null || right == null)
{
frame.Push(null);
}
else
{
frame.Push((ushort)left == (ushort)right);
}
return 1;
}
}
private sealed class EqualUInt32LiftedToNull : EqualInstruction
{
public override int Run(InterpretedFrame frame)
{
object? right = frame.Pop();
object? left = frame.Pop();
if (left == null || right == null)
{
frame.Push(null);
}
else
{
frame.Push((uint)left == (uint)right);
}
return 1;
}
}
private sealed class EqualUInt64LiftedToNull : EqualInstruction
{
public override int Run(InterpretedFrame frame)
{
object? right = frame.Pop();
object? left = frame.Pop();
if (left == null || right == null)
{
frame.Push(null);
}
else
{
frame.Push((ulong)left == (ulong)right);
}
return 1;
}
}
private sealed class EqualSingleLiftedToNull : EqualInstruction
{
public override int Run(InterpretedFrame frame)
{
object? right = frame.Pop();
object? left = frame.Pop();
if (left == null || right == null)
{
frame.Push(null);
}
else
{
frame.Push((float)left == (float)right);
}
return 1;
}
}
private sealed class EqualDoubleLiftedToNull : EqualInstruction
{
public override int Run(InterpretedFrame frame)
{
object? right = frame.Pop();
object? left = frame.Pop();
if (left == null || right == null)
{
frame.Push(null);
}
else
{
frame.Push((double)left == (double)right);
}
return 1;
}
}
public static Instruction Create(Type type, bool liftedToNull)
{
if (liftedToNull)
{
switch (type.GetNonNullableType().GetTypeCode())
{
case TypeCode.Boolean: return s_BooleanLiftedToNull ??= new EqualBooleanLiftedToNull();
case TypeCode.SByte: return s_SByteLiftedToNull ??= new EqualSByteLiftedToNull();
case TypeCode.Int16: return s_Int16LiftedToNull ??= new EqualInt16LiftedToNull();
case TypeCode.Char: return s_CharLiftedToNull ??= new EqualCharLiftedToNull();
case TypeCode.Int32: return s_Int32LiftedToNull ??= new EqualInt32LiftedToNull();
case TypeCode.Int64: return s_Int64LiftedToNull ??= new EqualInt64LiftedToNull();
case TypeCode.Byte: return s_ByteLiftedToNull ??= new EqualByteLiftedToNull();
case TypeCode.UInt16: return s_UInt16LiftedToNull ??= new EqualUInt16LiftedToNull();
case TypeCode.UInt32: return s_UInt32LiftedToNull ??= new EqualUInt32LiftedToNull();
case TypeCode.UInt64: return s_UInt64LiftedToNull ??= new EqualUInt64LiftedToNull();
case TypeCode.Single: return s_SingleLiftedToNull ??= new EqualSingleLiftedToNull();
default:
Debug.Assert(type.GetNonNullableType().GetTypeCode() == TypeCode.Double);
return s_DoubleLiftedToNull ??= new EqualDoubleLiftedToNull();
}
}
else
{
switch (type.GetNonNullableType().GetTypeCode())
{
case TypeCode.Boolean: return s_Boolean ??= new EqualBoolean();
case TypeCode.SByte: return s_SByte ??= new EqualSByte();
case TypeCode.Int16: return s_Int16 ??= new EqualInt16();
case TypeCode.Char: return s_Char ??= new EqualChar();
case TypeCode.Int32: return s_Int32 ??= new EqualInt32();
case TypeCode.Int64: return s_Int64 ??= new EqualInt64();
case TypeCode.Byte: return s_Byte ??= new EqualByte();
case TypeCode.UInt16: return s_UInt16 ??= new EqualUInt16();
case TypeCode.UInt32: return s_UInt32 ??= new EqualUInt32();
case TypeCode.UInt64: return s_UInt64 ??= new EqualUInt64();
case TypeCode.Single: return s_Single ??= new EqualSingle();
case TypeCode.Double: return s_Double ??= new EqualDouble();
default:
// Nullable only valid if one operand is constant null, so this assert is slightly too broad.
Debug.Assert(type.IsNullableOrReferenceType());
return s_reference ??= new EqualReference();
}
}
}
}
}
|