The Labs \ Source Viewer \ SSCLI \ Microsoft.JScript \ StrictEquality

  1. // ==++==
  2. //
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. //
  14. // ==--==
  15. namespace Microsoft.JScript
  16. {
  17.    
  18.     using Microsoft.JScript.Vsa;
  19.     using System;
  20.     using System.Reflection;
  21.     using System.Reflection.Emit;
  22.    
  23.     public class StrictEquality : BinaryOp
  24.     {
  25.        
  26.         internal StrictEquality(Context context, AST operand1, AST operand2, JSToken operatorTok) : base(context, operand1, operand2, operatorTok)
  27.         {
  28.         }
  29.        
  30.         internal override object Evaluate()
  31.         {
  32.             bool result = JScriptStrictEquals(this.operand1.Evaluate(), this.operand2.Evaluate(), VsaEngine.executeForJSEE);
  33.             if (this.operatorTok == JSToken.StrictEqual)
  34.                 return result;
  35.             else
  36.                 return !result;
  37.         }
  38.        
  39.         public static bool JScriptStrictEquals(object v1, object v2)
  40.         {
  41.             return StrictEquality.JScriptStrictEquals(v1, v2, false);
  42.         }
  43.        
  44.         static internal bool JScriptStrictEquals(object v1, object v2, bool checkForDebuggerObjects)
  45.         {
  46.             IConvertible ic1 = Convert.GetIConvertible(v1);
  47.             IConvertible ic2 = Convert.GetIConvertible(v2);
  48.             TypeCode t1 = Convert.GetTypeCode(v1, ic1);
  49.             TypeCode t2 = Convert.GetTypeCode(v2, ic2);
  50.             return StrictEquality.JScriptStrictEquals(v1, v2, ic1, ic2, t1, t2, checkForDebuggerObjects);
  51.         }
  52.        
  53.         static internal bool JScriptStrictEquals(object v1, object v2, IConvertible ic1, IConvertible ic2, TypeCode t1, TypeCode t2, bool checkForDebuggerObjects)
  54.         {
  55.             switch (t1) {
  56.                 case TypeCode.Empty:
  57.                     return t2 == TypeCode.Empty;
  58.                 case TypeCode.Object:
  59.                     if (v1 == v2)
  60.                         return true;
  61.                     if (v1 is Missing || v1 is System.Reflection.Missing)
  62.                         v1 = null;
  63.                     if (v1 == v2)
  64.                         return true;
  65.                     if (v2 is Missing || v2 is System.Reflection.Missing)
  66.                         v2 = null;
  67.                     return v1 == v2;
  68.                 case TypeCode.DBNull:
  69.                     return t2 == TypeCode.DBNull;
  70.                 case TypeCode.Boolean:
  71.                     return t2 == TypeCode.Boolean && ic1.ToBoolean(null) == ic2.ToBoolean(null);
  72.                 case TypeCode.Char:
  73.                    
  74.                     char ch = ic1.ToChar(null);
  75.                     switch (t2) {
  76.                         case TypeCode.Char:
  77.                             return ch == ic2.ToChar(null);
  78.                         case TypeCode.SByte:
  79.                         case TypeCode.Byte:
  80.                         case TypeCode.Int16:
  81.                         case TypeCode.UInt16:
  82.                         case TypeCode.Int32:
  83.                         case TypeCode.UInt32:
  84.                         case TypeCode.Int64:
  85.                             return ch == ic2.ToInt64(null);
  86.                         case TypeCode.UInt64:
  87.                             return ch == ic2.ToUInt64(null);
  88.                         case TypeCode.Single:
  89.                         case TypeCode.Double:
  90.                             return ch == ic2.ToDouble(null);
  91.                         case TypeCode.Decimal:
  92.                             return ((decimal)(int)ch) == ic2.ToDecimal(null);
  93.                         case TypeCode.String:
  94.                             string str = ic2.ToString(null);
  95.                             return str.Length == 1 && ch == str[0];
  96.                     }
  97.                     return false;
  98.                 case TypeCode.SByte:
  99.                    
  100.                     sbyte sb1 = ic1.ToSByte(null);
  101.                     switch (t2) {
  102.                         case TypeCode.Char:
  103.                             return sb1 == ic2.ToChar(null);
  104.                         case TypeCode.SByte:
  105.                         case TypeCode.Byte:
  106.                         case TypeCode.Int16:
  107.                         case TypeCode.UInt16:
  108.                         case TypeCode.Int32:
  109.                         case TypeCode.UInt32:
  110.                         case TypeCode.Int64:
  111.                             return sb1 == ic2.ToInt64(null);
  112.                         case TypeCode.UInt64:
  113.                             return sb1 >= 0 && ((UInt64)sb1) == ic2.ToUInt64(null);
  114.                         case TypeCode.Single:
  115.                             return sb1 == ic2.ToSingle(null);
  116.                         case TypeCode.Double:
  117.                             return sb1 == ic2.ToDouble(null);
  118.                         case TypeCode.Decimal:
  119.                             return ((decimal)sb1) == ic2.ToDecimal(null);
  120.                     }
  121.                     return false;
  122.                 case TypeCode.Byte:
  123.                    
  124.                     byte b1 = ic1.ToByte(null);
  125.                     switch (t2) {
  126.                         case TypeCode.Char:
  127.                             return b1 == ic2.ToChar(null);
  128.                         case TypeCode.SByte:
  129.                         case TypeCode.Byte:
  130.                         case TypeCode.Int16:
  131.                         case TypeCode.UInt16:
  132.                         case TypeCode.Int32:
  133.                         case TypeCode.UInt32:
  134.                         case TypeCode.Int64:
  135.                             return b1 == ic2.ToInt64(null);
  136.                         case TypeCode.UInt64:
  137.                             return b1 == ic2.ToUInt64(null);
  138.                         case TypeCode.Single:
  139.                             return b1 == ic2.ToSingle(null);
  140.                         case TypeCode.Double:
  141.                             return b1 == ic2.ToDouble(null);
  142.                         case TypeCode.Decimal:
  143.                             return ((decimal)b1) == ic2.ToDecimal(null);
  144.                     }
  145.                     return false;
  146.                 case TypeCode.Int16:
  147.                    
  148.                     Int16 s1 = ic1.ToInt16(null);
  149.                     switch (t2) {
  150.                         case TypeCode.Char:
  151.                             return s1 == ic2.ToChar(null);
  152.                         case TypeCode.SByte:
  153.                         case TypeCode.Byte:
  154.                         case TypeCode.Int16:
  155.                         case TypeCode.UInt16:
  156.                         case TypeCode.Int32:
  157.                         case TypeCode.UInt32:
  158.                         case TypeCode.Int64:
  159.                             return s1 == ic2.ToInt64(null);
  160.                         case TypeCode.UInt64:
  161.                             return s1 >= 0 && ((UInt64)s1) == ic2.ToUInt64(null);
  162.                         case TypeCode.Single:
  163.                             return s1 == ic2.ToSingle(null);
  164.                         case TypeCode.Double:
  165.                             return s1 == ic2.ToDouble(null);
  166.                         case TypeCode.Decimal:
  167.                             return ((decimal)s1) == ic2.ToDecimal(null);
  168.                     }
  169.                     return false;
  170.                 case TypeCode.UInt16:
  171.                    
  172.                     UInt16 us1 = ic1.ToUInt16(null);
  173.                     switch (t2) {
  174.                         case TypeCode.Char:
  175.                             return us1 == ic2.ToChar(null);
  176.                         case TypeCode.SByte:
  177.                         case TypeCode.Byte:
  178.                         case TypeCode.Int16:
  179.                         case TypeCode.UInt16:
  180.                         case TypeCode.Int32:
  181.                         case TypeCode.UInt32:
  182.                         case TypeCode.Int64:
  183.                             return us1 == ic2.ToInt64(null);
  184.                         case TypeCode.UInt64:
  185.                             return us1 == ic2.ToUInt64(null);
  186.                         case TypeCode.Single:
  187.                             return us1 == ic2.ToSingle(null);
  188.                         case TypeCode.Double:
  189.                             return us1 == ic2.ToDouble(null);
  190.                         case TypeCode.Decimal:
  191.                             return ((decimal)us1) == ic2.ToDecimal(null);
  192.                     }
  193.                     return false;
  194.                 case TypeCode.Int32:
  195.                    
  196.                     Int32 i1 = ic1.ToInt32(null);
  197.                     switch (t2) {
  198.                         case TypeCode.Char:
  199.                             return i1 == ic2.ToChar(null);
  200.                         case TypeCode.SByte:
  201.                         case TypeCode.Byte:
  202.                         case TypeCode.Int16:
  203.                         case TypeCode.UInt16:
  204.                         case TypeCode.Int32:
  205.                         case TypeCode.UInt32:
  206.                         case TypeCode.Int64:
  207.                             return i1 == ic2.ToInt64(null);
  208.                         case TypeCode.UInt64:
  209.                             return i1 >= 0 && ((UInt64)i1) == ic2.ToUInt64(null);
  210.                         case TypeCode.Single:
  211.                             return i1 == ic2.ToSingle(null);
  212.                         case TypeCode.Double:
  213.                             return i1 == ic2.ToDouble(null);
  214.                         case TypeCode.Decimal:
  215.                             return ((decimal)i1) == ic2.ToDecimal(null);
  216.                     }
  217.                     return false;
  218.                 case TypeCode.UInt32:
  219.                    
  220.                     UInt32 ui1 = ic1.ToUInt32(null);
  221.                     switch (t2) {
  222.                         case TypeCode.Char:
  223.                             return ui1 == ic2.ToChar(null);
  224.                         case TypeCode.SByte:
  225.                         case TypeCode.Byte:
  226.                         case TypeCode.Int16:
  227.                         case TypeCode.UInt16:
  228.                         case TypeCode.Int32:
  229.                         case TypeCode.UInt32:
  230.                         case TypeCode.Int64:
  231.                             return ui1 == ic2.ToInt64(null);
  232.                         case TypeCode.UInt64:
  233.                             return ui1 == ic2.ToUInt64(null);
  234.                         case TypeCode.Single:
  235.                             return ui1 == ic2.ToSingle(null);
  236.                         case TypeCode.Double:
  237.                             return ui1 == ic2.ToDouble(null);
  238.                         case TypeCode.Decimal:
  239.                             return ((decimal)ui1) == ic2.ToDecimal(null);
  240.                     }
  241.                     return false;
  242.                 case TypeCode.Int64:
  243.                    
  244.                     Int64 l1 = ic1.ToInt64(null);
  245.                     switch (t2) {
  246.                         case TypeCode.Char:
  247.                             return l1 == ic2.ToChar(null);
  248.                         case TypeCode.SByte:
  249.                         case TypeCode.Byte:
  250.                         case TypeCode.Int16:
  251.                         case TypeCode.UInt16:
  252.                         case TypeCode.Int32:
  253.                         case TypeCode.UInt32:
  254.                         case TypeCode.Int64:
  255.                             return l1 == ic2.ToInt64(null);
  256.                         case TypeCode.UInt64:
  257.                             return l1 >= 0 && ((UInt64)l1) == ic2.ToUInt64(null);
  258.                         case TypeCode.Single:
  259.                             return l1 == ic2.ToSingle(null);
  260.                         case TypeCode.Double:
  261.                             return l1 == ic2.ToDouble(null);
  262.                         case TypeCode.Decimal:
  263.                             return ((decimal)l1) == ic2.ToDecimal(null);
  264.                     }
  265.                     return false;
  266.                 case TypeCode.UInt64:
  267.                    
  268.                     UInt64 ul1 = ic1.ToUInt64(null);
  269.                     switch (t2) {
  270.                         case TypeCode.Char:
  271.                             return ul1 == ic2.ToChar(null);
  272.                         case TypeCode.SByte:
  273.                         case TypeCode.Byte:
  274.                         case TypeCode.Int16:
  275.                         case TypeCode.UInt16:
  276.                         case TypeCode.Int32:
  277.                         case TypeCode.UInt32:
  278.                         case TypeCode.Int64:
  279.                             l1 = ic2.ToInt64(null);
  280.                             return l1 >= 0 && ul1 == (UInt64)l1;
  281.                         case TypeCode.UInt64:
  282.                             return ul1 == ic2.ToUInt64(null);
  283.                         case TypeCode.Single:
  284.                             return ul1 == ic2.ToSingle(null);
  285.                         case TypeCode.Double:
  286.                             return ul1 == ic2.ToDouble(null);
  287.                         case TypeCode.Decimal:
  288.                             return ((decimal)ul1) == ic2.ToDecimal(null);
  289.                     }
  290.                     return false;
  291.                 case TypeCode.Single:
  292.                    
  293.                     float f1 = ic1.ToSingle(null);
  294.                     switch (t2) {
  295.                         case TypeCode.Char:
  296.                             return f1 == ic2.ToChar(null);
  297.                         case TypeCode.SByte:
  298.                         case TypeCode.Byte:
  299.                         case TypeCode.Int16:
  300.                         case TypeCode.UInt16:
  301.                         case TypeCode.Int32:
  302.                         case TypeCode.UInt32:
  303.                         case TypeCode.Int64:
  304.                             return f1 == ic2.ToInt64(null);
  305.                         case TypeCode.UInt64:
  306.                             return f1 == ic2.ToUInt64(null);
  307.                         case TypeCode.Single:
  308.                             return f1 == ic2.ToSingle(null);
  309.                         case TypeCode.Double:
  310.                             return f1 == ic2.ToSingle(null);
  311.                         case TypeCode.Decimal:
  312.                             return ((decimal)f1) == ic2.ToDecimal(null);
  313.                     }
  314.                     return false;
  315.                 case TypeCode.Double:
  316.                    
  317.                     double d1 = ic1.ToDouble(null);
  318.                     switch (t2) {
  319.                         case TypeCode.Char:
  320.                             return d1 == ic2.ToChar(null);
  321.                         case TypeCode.SByte:
  322.                         case TypeCode.Byte:
  323.                         case TypeCode.Int16:
  324.                         case TypeCode.UInt16:
  325.                         case TypeCode.Int32:
  326.                         case TypeCode.UInt32:
  327.                         case TypeCode.Int64:
  328.                             return d1 == ic2.ToInt64(null);
  329.                         case TypeCode.UInt64:
  330.                             return d1 == ic2.ToUInt64(null);
  331.                         case TypeCode.Single:
  332.                             return ((float)d1) == ic2.ToSingle(null);
  333.                         case TypeCode.Double:
  334.                             return d1 == ic2.ToDouble(null);
  335.                         case TypeCode.Decimal:
  336.                             return ((decimal)d1) == ic2.ToDecimal(null);
  337.                     }
  338.                     return false;
  339.                 case TypeCode.Decimal:
  340.                    
  341.                     decimal de1 = ic1.ToDecimal(null);
  342.                     switch (t2) {
  343.                         case TypeCode.Char:
  344.                             return de1 == (decimal)(int)ic2.ToChar(null);
  345.                         case TypeCode.SByte:
  346.                         case TypeCode.Byte:
  347.                         case TypeCode.Int16:
  348.                         case TypeCode.UInt16:
  349.                         case TypeCode.Int32:
  350.                         case TypeCode.UInt32:
  351.                         case TypeCode.Int64:
  352.                             return de1 == ic2.ToInt64(null);
  353.                         case TypeCode.UInt64:
  354.                             return de1 == ic2.ToUInt64(null);
  355.                         case TypeCode.Single:
  356.                             return de1 == (decimal)ic2.ToSingle(null);
  357.                         case TypeCode.Double:
  358.                             return de1 == (decimal)ic2.ToDouble(null);
  359.                         case TypeCode.Decimal:
  360.                             return de1 == ic2.ToDecimal(null);
  361.                     }
  362.                     return false;
  363.                 case TypeCode.DateTime:
  364.                    
  365.                     return t2 == TypeCode.DateTime && ic1.ToDateTime(null) == ic2.ToDateTime(null);
  366.                 case TypeCode.String:
  367.                     if (t2 == TypeCode.Char) {
  368.                         string str = ic1.ToString(null);
  369.                         return str.Length == 1 && str[0] == ic2.ToChar(null);
  370.                     }
  371.                     return t2 == TypeCode.String && (v1 == v2 || ic1.ToString(null).Equals(ic2.ToString(null)));
  372.             }
  373.             return false;
  374.             //should never get here
  375.         }
  376.        
  377.         internal override IReflect InferType(JSField inference_target)
  378.         {
  379.             return Typeob.Boolean;
  380.         }
  381.        
  382.         internal override void TranslateToConditionalBranch(ILGenerator il, bool branchIfTrue, Label label, bool shortForm)
  383.         {
  384.             Type t1 = Convert.ToType(this.operand1.InferType(null));
  385.             Type t2 = Convert.ToType(this.operand2.InferType(null));
  386.             if (this.operand1 is ConstantWrapper)
  387.                 if (this.operand1.Evaluate() == null)
  388.                     t1 = Typeob.Empty;
  389.             if (this.operand2 is ConstantWrapper)
  390.                 if (this.operand2.Evaluate() == null)
  391.                     t2 = Typeob.Empty;
  392.             if (t1 != t2 && t1.IsPrimitive && t2.IsPrimitive) {
  393.                 if (t1 == Typeob.Single)
  394.                     t2 = t1;
  395.                 else if (t2 == Typeob.Single)
  396.                     t1 = t2;
  397.                 else if (Convert.IsPromotableTo(t2, t1))
  398.                     t2 = t1;
  399.                 else if (Convert.IsPromotableTo(t1, t2))
  400.                     t1 = t2;
  401.             }
  402.             bool nonPrimitive = true;
  403.             if (t1 == t2 && t1 != Typeob.Object) {
  404.                 // Operand types are equal and not Object - need to compare values only. Primitive
  405.                 // values get compared with IL instructions; other values including value types
  406.                 // get compared with Object.Equals. String is special cased for perf.
  407.                 Type t = t1;
  408.                 if (!t1.IsPrimitive)
  409.                     t = Typeob.Object;
  410.                 this.operand1.TranslateToIL(il, t);
  411.                 this.operand2.TranslateToIL(il, t);
  412.                 if (t1 == Typeob.String)
  413.                     il.Emit(OpCodes.Call, CompilerGlobals.stringEqualsMethod);
  414.                 else if (!t1.IsPrimitive)
  415.                     il.Emit(OpCodes.Callvirt, CompilerGlobals.equalsMethod);
  416.                 else
  417.                     nonPrimitive = false;
  418.             }
  419.             else if (t1 == Typeob.Empty) {
  420.                 this.operand2.TranslateToIL(il, Typeob.Object);
  421.                 branchIfTrue = !branchIfTrue;
  422.             }
  423.             else if (t2 == Typeob.Empty) {
  424.                 this.operand1.TranslateToIL(il, Typeob.Object);
  425.                 branchIfTrue = !branchIfTrue;
  426.             }
  427.             else {
  428.                 this.operand1.TranslateToIL(il, Typeob.Object);
  429.                 this.operand2.TranslateToIL(il, Typeob.Object);
  430.                 il.Emit(OpCodes.Call, CompilerGlobals.jScriptStrictEqualsMethod);
  431.             }
  432.             if (branchIfTrue) {
  433.                 if (this.operatorTok == JSToken.StrictEqual)
  434.                     if (nonPrimitive)
  435.                         il.Emit(shortForm ? OpCodes.Brtrue_S : OpCodes.Brtrue, label);
  436.                     else
  437.                         il.Emit(shortForm ? OpCodes.Beq_S : OpCodes.Beq, label);
  438.                 else if (nonPrimitive)
  439.                     il.Emit(shortForm ? OpCodes.Brfalse_S : OpCodes.Brfalse, label);
  440.                 else
  441.                     il.Emit(shortForm ? OpCodes.Bne_Un_S : OpCodes.Bne_Un, label);
  442.             }
  443.             else {
  444.                 if (this.operatorTok == JSToken.StrictEqual)
  445.                     if (nonPrimitive)
  446.                         il.Emit(shortForm ? OpCodes.Brfalse_S : OpCodes.Brfalse, label);
  447.                     else
  448.                         il.Emit(shortForm ? OpCodes.Bne_Un_S : OpCodes.Bne_Un, label);
  449.                 else if (nonPrimitive)
  450.                     il.Emit(shortForm ? OpCodes.Brtrue_S : OpCodes.Brtrue, label);
  451.                 else
  452.                     il.Emit(shortForm ? OpCodes.Beq_S : OpCodes.Beq, label);
  453.             }
  454.             return;
  455.         }
  456.        
  457.         internal override void TranslateToIL(ILGenerator il, Type rtype)
  458.         {
  459.             Label true_label = il.DefineLabel();
  460.             Label done_label = il.DefineLabel();
  461.             this.TranslateToConditionalBranch(il, true, true_label, true);
  462.             il.Emit(OpCodes.Ldc_I4_0);
  463.             il.Emit(OpCodes.Br_S, done_label);
  464.             il.MarkLabel(true_label);
  465.             il.Emit(OpCodes.Ldc_I4_1);
  466.             il.MarkLabel(done_label);
  467.             Convert.Emit(this, il, Typeob.Boolean, rtype);
  468.         }
  469.     }
  470. }

Developer Fusion