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

  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 System;
  19.     using System.Reflection;
  20.     using System.Reflection.Emit;
  21.     using System.Diagnostics;
  22.    
  23.     internal enum PostOrPrefix
  24.     {
  25.         PostfixDecrement,
  26.         PostfixIncrement,
  27.         PrefixDecrement,
  28.         PrefixIncrement
  29.     }
  30.    
  31.     public class PostOrPrefixOperator : UnaryOp
  32.     {
  33.         private MethodInfo operatorMeth;
  34.         private PostOrPrefix operatorTok;
  35.         private object metaData;
  36.         private Type type;
  37.        
  38.         internal PostOrPrefixOperator(Context context, AST operand) : base(context, operand)
  39.         {
  40.         }
  41.        
  42.         internal PostOrPrefixOperator(Context context, AST operand, PostOrPrefix operatorTok) : base(context, operand)
  43.         {
  44.             this.operatorMeth = null;
  45.             this.operatorTok = operatorTok;
  46.             this.metaData = null;
  47.             this.type = null;
  48.         }
  49.        
  50.         public PostOrPrefixOperator(int operatorTok) : this(null, null, (PostOrPrefix)operatorTok)
  51.         {
  52.         }
  53.        
  54.         private object DoOp(int i)
  55.         {
  56.             switch (this.operatorTok) {
  57.                 case PostOrPrefix.PostfixIncrement:
  58.                 case PostOrPrefix.PrefixIncrement:
  59.                     if (i == int.MaxValue)
  60.                         return (double)int.MaxValue + 1.0;
  61.                     return i + 1;
  62.                 default:
  63.                     if (i == int.MinValue)
  64.                         return (double)int.MinValue - 1.0;
  65.                     return i - 1;
  66.             }
  67.         }
  68.        
  69.         private object DoOp(uint i)
  70.         {
  71.             switch (this.operatorTok) {
  72.                 case PostOrPrefix.PostfixIncrement:
  73.                 case PostOrPrefix.PrefixIncrement:
  74.                     if (i == uint.MaxValue)
  75.                         return (double)uint.MaxValue + 1.0;
  76.                     return i + 1;
  77.                 default:
  78.                     if (i == uint.MinValue)
  79.                         return (double)uint.MinValue - 1.0;
  80.                     return i - 1;
  81.             }
  82.         }
  83.        
  84.         private object DoOp(long i)
  85.         {
  86.             switch (this.operatorTok) {
  87.                 case PostOrPrefix.PostfixIncrement:
  88.                 case PostOrPrefix.PrefixIncrement:
  89.                     if (i == long.MaxValue)
  90.                         return (double)long.MaxValue + 1.0;
  91.                     return i + 1;
  92.                 default:
  93.                     if (i == long.MinValue)
  94.                         return (double)long.MinValue - 1.0;
  95.                     return i - 1;
  96.             }
  97.         }
  98.        
  99.         private object DoOp(ulong i)
  100.         {
  101.             switch (this.operatorTok) {
  102.                 case PostOrPrefix.PostfixIncrement:
  103.                 case PostOrPrefix.PrefixIncrement:
  104.                     if (i == ulong.MaxValue)
  105.                         return (double)ulong.MaxValue + 1.0;
  106.                     return i + 1;
  107.                 default:
  108.                     if (i == ulong.MinValue)
  109.                         return (double)ulong.MinValue - 1.0;
  110.                     return i - 1;
  111.             }
  112.         }
  113.        
  114.         private object DoOp(double d)
  115.         {
  116.             switch (this.operatorTok) {
  117.                 case PostOrPrefix.PostfixIncrement:
  118.                 case PostOrPrefix.PrefixIncrement:
  119.                     return d + 1;
  120.                 default:
  121.                     return d - 1;
  122.             }
  123.         }
  124.        
  125.         internal override object Evaluate()
  126.         {
  127.             try {
  128.                 object oldval = this.operand.Evaluate();
  129.                 object newval = this.EvaluatePostOrPrefix(ref oldval);
  130.                 this.operand.SetValue(newval);
  131.                 switch (this.operatorTok) {
  132.                     case PostOrPrefix.PostfixDecrement:
  133.                     case PostOrPrefix.PostfixIncrement:
  134.                         return oldval;
  135.                     case PostOrPrefix.PrefixDecrement:
  136.                     case PostOrPrefix.PrefixIncrement:
  137.                         return newval;
  138.                     default:
  139.                         throw new JScriptException(JSError.InternalError, this.context);
  140.                         break;
  141.                 }
  142.             }
  143.             catch (JScriptException e) {
  144.                 if (e.context == null)
  145.                     e.context = this.context;
  146.                 throw e;
  147.             }
  148.             catch (Exception e) {
  149.                 throw new JScriptException(e, this.context);
  150.             }
  151.             catch {
  152.                 throw new JScriptException(JSError.NonClsException, this.context);
  153.             }
  154.         }
  155.        
  156.         #if !DEBUG
  157.         [DebuggerStepThroughAttribute()]
  158.         [DebuggerHiddenAttribute()]
  159.         #endif
  160.         public object EvaluatePostOrPrefix(ref object v)
  161.         {
  162.             int i;
  163.             uint ui;
  164.             long l;
  165.             ulong ul;
  166.             double d;
  167.             IConvertible ic = Convert.GetIConvertible(v);
  168.             switch (Convert.GetTypeCode(v, ic)) {
  169.                 case TypeCode.Empty:
  170.                     v = Double.NaN;
  171.                     return v;
  172.                 case TypeCode.DBNull:
  173.                     v = 0;
  174.                     return this.DoOp(0);
  175.                 case TypeCode.Boolean:
  176.                 case TypeCode.SByte:
  177.                 case TypeCode.Byte:
  178.                 case TypeCode.Int16:
  179.                 case TypeCode.UInt16:
  180.                 case TypeCode.Int32:
  181.                     v = i = ic.ToInt32(null);
  182.                     return this.DoOp(i);
  183.                 case TypeCode.Char:
  184.                     i = ic.ToInt32(null);
  185.                     return ((IConvertible)this.DoOp(i)).ToChar(null);
  186.                 case TypeCode.UInt32:
  187.                     v = ui = ic.ToUInt32(null);
  188.                     return this.DoOp(ui);
  189.                 case TypeCode.Int64:
  190.                     v = l = ic.ToInt64(null);
  191.                     return this.DoOp(l);
  192.                 case TypeCode.UInt64:
  193.                     v = ul = ic.ToUInt64(null);
  194.                     return this.DoOp(ul);
  195.                 case TypeCode.Single:
  196.                 case TypeCode.Double:
  197.                     v = d = ic.ToDouble(null);
  198.                     return this.DoOp(d);
  199.             }
  200.             MethodInfo oper = this.GetOperator(v.GetType());
  201.             if (oper != null)
  202.                 return oper.Invoke(null, (BindingFlags)0, JSBinder.ob, new object[] {v}, null);
  203.             else {
  204.                 v = d = Convert.ToNumber(v, ic);
  205.                 return this.DoOp(d);
  206.             }
  207.         }
  208.        
  209.         private MethodInfo GetOperator(IReflect ir)
  210.         {
  211.             Type t = ir is Type ? (Type)ir : Typeob.Object;
  212.             if (this.type == t)
  213.                 return this.operatorMeth;
  214.             this.type = t;
  215.             if (Convert.IsPrimitiveNumericType(t) || Typeob.JSObject.IsAssignableFrom(t)) {
  216.                 this.operatorMeth = null;
  217.                 return null;
  218.             }
  219.             switch (this.operatorTok) {
  220.                 case PostOrPrefix.PostfixDecrement:
  221.                 case PostOrPrefix.PrefixDecrement:
  222.                     this.operatorMeth = t.GetMethod("op_Decrement", BindingFlags.Public | BindingFlags.Static, JSBinder.ob, new Type[] {t}, null);
  223.                     break;
  224.                 case PostOrPrefix.PostfixIncrement:
  225.                 case PostOrPrefix.PrefixIncrement:
  226.                     this.operatorMeth = t.GetMethod("op_Increment", BindingFlags.Public | BindingFlags.Static, JSBinder.ob, new Type[] {t}, null);
  227.                     break;
  228.                 default:
  229.                     throw new JScriptException(JSError.InternalError, this.context);
  230.                     break;
  231.             }
  232.             if (this.operatorMeth != null && (!this.operatorMeth.IsStatic || (operatorMeth.Attributes & MethodAttributes.SpecialName) == (MethodAttributes)0 || operatorMeth.GetParameters().Length != 1))
  233.                 this.operatorMeth = null;
  234.             if (this.operatorMeth != null)
  235.                 this.operatorMeth = new JSMethodInfo(this.operatorMeth);
  236.             return this.operatorMeth;
  237.         }
  238.        
  239.         internal override IReflect InferType(JSField inference_target)
  240.         {
  241.             Debug.Assert(Globals.TypeRefs.InReferenceContext(this.type));
  242.             MethodInfo oper;
  243.             if (this.type == null || inference_target != null) {
  244.                 oper = this.GetOperator(this.operand.InferType(inference_target));
  245.             }
  246.             else
  247.                 oper = this.GetOperator(this.type);
  248.             if (oper != null) {
  249.                 this.metaData = oper;
  250.                 return oper.ReturnType;
  251.             }
  252.             if (Convert.IsPrimitiveNumericType(this.type))
  253.                 return this.type;
  254.             else if (this.type == Typeob.Char)
  255.                 return this.type;
  256.             else if (Typeob.JSObject.IsAssignableFrom(this.type))
  257.                 return Typeob.Double;
  258.             else
  259.                 return Typeob.Object;
  260.         }
  261.        
  262.         internal override AST PartiallyEvaluate()
  263.         {
  264.             this.operand = this.operand.PartiallyEvaluateAsReference();
  265.             this.operand.SetPartialValue(this);
  266.             return this;
  267.         }
  268.        
  269.         private void TranslateToILForNoOverloadCase(ILGenerator il, Type rtype)
  270.         {
  271.             Type type = Convert.ToType(this.operand.InferType(null));
  272.             this.operand.TranslateToILPreSetPlusGet(il);
  273.             if (rtype == Typeob.Void) {
  274.                 Type rt = Typeob.Double;
  275.                 if (Convert.IsPrimitiveNumericType(type))
  276.                     if (type == Typeob.SByte || type == Typeob.Int16)
  277.                         rt = Typeob.Int32;
  278.                     else if (type == Typeob.Byte || type == Typeob.UInt16 || type == Typeob.Char)
  279.                         rt = Typeob.UInt32;
  280.                     else
  281.                         rt = type;
  282.                 Convert.Emit(this, il, type, rt);
  283.                 il.Emit(OpCodes.Ldc_I4_1);
  284.                 Convert.Emit(this, il, Typeob.Int32, rt);
  285.                 if (rt == Typeob.Double || rt == Typeob.Single) {
  286.                     if (this.operatorTok == PostOrPrefix.PostfixDecrement || this.operatorTok == PostOrPrefix.PrefixDecrement) {
  287.                         il.Emit(OpCodes.Sub);
  288.                     }
  289.                     else {
  290.                         il.Emit(OpCodes.Add);
  291.                     }
  292.                 }
  293.                 else if (rt == Typeob.Int32 || rt == Typeob.Int64) {
  294.                     if (this.operatorTok == PostOrPrefix.PostfixDecrement || this.operatorTok == PostOrPrefix.PrefixDecrement) {
  295.                         il.Emit(OpCodes.Sub_Ovf);
  296.                     }
  297.                     else {
  298.                         il.Emit(OpCodes.Add_Ovf);
  299.                     }
  300.                 }
  301.                 else {
  302.                     if (this.operatorTok == PostOrPrefix.PostfixDecrement || this.operatorTok == PostOrPrefix.PrefixDecrement) {
  303.                         il.Emit(OpCodes.Sub_Ovf_Un);
  304.                     }
  305.                     else {
  306.                         il.Emit(OpCodes.Add_Ovf_Un);
  307.                     }
  308.                 }
  309.                 Convert.Emit(this, il, rt, type);
  310.                 this.operand.TranslateToILSet(il);
  311.             }
  312.             else {
  313.                 //set rt to be the smallest type that is precise enough for the result and the variable
  314.                 Type rt = Typeob.Double;
  315.                 if (Convert.IsPrimitiveNumericType(rtype) && Convert.IsPromotableTo(type, rtype))
  316.                     rt = rtype;
  317.                 else if (Convert.IsPrimitiveNumericType(type) && Convert.IsPromotableTo(rtype, type))
  318.                     rt = type;
  319.                 if (rt == Typeob.SByte || rt == Typeob.Int16)
  320.                     rt = Typeob.Int32;
  321.                 else if (rt == Typeob.Byte || rt == Typeob.UInt16 || rt == Typeob.Char)
  322.                     rt = Typeob.UInt32;
  323.                 LocalBuilder result = il.DeclareLocal(rtype);
  324.                 Convert.Emit(this, il, type, rt);
  325.                 if (this.operatorTok == PostOrPrefix.PostfixDecrement) {
  326.                     il.Emit(OpCodes.Dup);
  327.                     if (type == Typeob.Char) {
  328.                         Convert.Emit(this, il, rt, Typeob.Char);
  329.                         Convert.Emit(this, il, Typeob.Char, rtype);
  330.                     }
  331.                     else
  332.                         Convert.Emit(this, il, rt, rtype);
  333.                     il.Emit(OpCodes.Stloc, result);
  334.                     il.Emit(OpCodes.Ldc_I4_1);
  335.                     Convert.Emit(this, il, Typeob.Int32, rt);
  336.                     if (rt == Typeob.Double || rt == Typeob.Single)
  337.                         il.Emit(OpCodes.Sub);
  338.                     else if (rt == Typeob.Int32 || rt == Typeob.Int64)
  339.                         il.Emit(OpCodes.Sub_Ovf);
  340.                     else
  341.                         il.Emit(OpCodes.Sub_Ovf_Un);
  342.                 }
  343.                 else if (this.operatorTok == PostOrPrefix.PostfixIncrement) {
  344.                     il.Emit(OpCodes.Dup);
  345.                     if (type == Typeob.Char) {
  346.                         Convert.Emit(this, il, rt, Typeob.Char);
  347.                         Convert.Emit(this, il, Typeob.Char, rtype);
  348.                     }
  349.                     else
  350.                         Convert.Emit(this, il, rt, rtype);
  351.                     il.Emit(OpCodes.Stloc, result);
  352.                     il.Emit(OpCodes.Ldc_I4_1);
  353.                     Convert.Emit(this, il, Typeob.Int32, rt);
  354.                     if (rt == Typeob.Double || rt == Typeob.Single)
  355.                         il.Emit(OpCodes.Add);
  356.                     else if (rt == Typeob.Int32 || rt == Typeob.Int64)
  357.                         il.Emit(OpCodes.Add_Ovf);
  358.                     else
  359.                         il.Emit(OpCodes.Add_Ovf_Un);
  360.                 }
  361.                 else if (this.operatorTok == PostOrPrefix.PrefixDecrement) {
  362.                     il.Emit(OpCodes.Ldc_I4_1);
  363.                     Convert.Emit(this, il, Typeob.Int32, rt);
  364.                     if (rt == Typeob.Double || rt == Typeob.Single)
  365.                         il.Emit(OpCodes.Sub);
  366.                     else if (rt == Typeob.Int32 || rt == Typeob.Int64)
  367.                         il.Emit(OpCodes.Sub_Ovf);
  368.                     else
  369.                         il.Emit(OpCodes.Sub_Ovf_Un);
  370.                     il.Emit(OpCodes.Dup);
  371.                     if (type == Typeob.Char) {
  372.                         Convert.Emit(this, il, rt, Typeob.Char);
  373.                         Convert.Emit(this, il, Typeob.Char, rtype);
  374.                     }
  375.                     else
  376.                         Convert.Emit(this, il, rt, rtype);
  377.                     il.Emit(OpCodes.Stloc, result);
  378.                 }
  379.                 else {
  380.                     //if (this.operatorTok == PostOrPrefix.PrefixIncrement)
  381.                     il.Emit(OpCodes.Ldc_I4_1);
  382.                     Convert.Emit(this, il, Typeob.Int32, rt);
  383.                     if (rt == Typeob.Double || rt == Typeob.Single)
  384.                         il.Emit(OpCodes.Add);
  385.                     else if (rt == Typeob.Int32 || rt == Typeob.Int64)
  386.                         il.Emit(OpCodes.Add_Ovf);
  387.                     else
  388.                         il.Emit(OpCodes.Add_Ovf_Un);
  389.                     il.Emit(OpCodes.Dup);
  390.                     if (type == Typeob.Char) {
  391.                         Convert.Emit(this, il, rt, Typeob.Char);
  392.                         Convert.Emit(this, il, Typeob.Char, rtype);
  393.                     }
  394.                     else
  395.                         Convert.Emit(this, il, rt, rtype);
  396.                     il.Emit(OpCodes.Stloc, result);
  397.                 }
  398.                 Convert.Emit(this, il, rt, type);
  399.                 this.operand.TranslateToILSet(il);
  400.                 il.Emit(OpCodes.Ldloc, result);
  401.             }
  402.         }
  403.        
  404.         internal override void TranslateToIL(ILGenerator il, Type rtype)
  405.         {
  406.             if (this.metaData == null) {
  407.                 TranslateToILForNoOverloadCase(il, rtype);
  408.                 return;
  409.             }
  410.             if (this.metaData is MethodInfo) {
  411.                 object result = null;
  412.                 Type type = Convert.ToType(this.operand.InferType(null));
  413.                 this.operand.TranslateToILPreSetPlusGet(il);
  414.                 if (rtype != Typeob.Void) {
  415.                     result = il.DeclareLocal(rtype);
  416.                     if (this.operatorTok == PostOrPrefix.PostfixDecrement || this.operatorTok == PostOrPrefix.PostfixIncrement) {
  417.                         il.Emit(OpCodes.Dup);
  418.                         Convert.Emit(this, il, type, rtype);
  419.                         il.Emit(OpCodes.Stloc, (LocalBuilder)result);
  420.                     }
  421.                 }
  422.                 MethodInfo oper = (MethodInfo)this.metaData;
  423.                 ParameterInfo[] pars = oper.GetParameters();
  424.                 Convert.Emit(this, il, type, pars[0].ParameterType);
  425.                 il.Emit(OpCodes.Call, oper);
  426.                 if (rtype != Typeob.Void) {
  427.                     if (this.operatorTok == PostOrPrefix.PrefixDecrement || this.operatorTok == PostOrPrefix.PrefixIncrement) {
  428.                         il.Emit(OpCodes.Dup);
  429.                         Convert.Emit(this, il, type, rtype);
  430.                         il.Emit(OpCodes.Stloc, (LocalBuilder)result);
  431.                     }
  432.                 }
  433.                 Convert.Emit(this, il, oper.ReturnType, type);
  434.                 this.operand.TranslateToILSet(il);
  435.                 if (rtype != Typeob.Void)
  436.                     il.Emit(OpCodes.Ldloc, (LocalBuilder)result);
  437.             }
  438.             else {
  439.                 //Getting here is just too bad. We do not know until the code runs whether or not to call an overloaded operator method.
  440.                 //Compile operands to objects and devolve the decision making to run time thunks
  441.                 Type type = Convert.ToType(this.operand.InferType(null));
  442.                 LocalBuilder result = il.DeclareLocal(Typeob.Object);
  443.                 this.operand.TranslateToILPreSetPlusGet(il);
  444.                 Convert.Emit(this, il, type, Typeob.Object);
  445.                 il.Emit(OpCodes.Stloc, result);
  446.                 il.Emit(OpCodes.Ldloc, (LocalBuilder)this.metaData);
  447.                 il.Emit(OpCodes.Ldloca, result);
  448.                 il.Emit(OpCodes.Call, CompilerGlobals.evaluatePostOrPrefixOperatorMethod);
  449.                 if (rtype != Typeob.Void) {
  450.                     if (this.operatorTok == PostOrPrefix.PrefixDecrement || this.operatorTok == PostOrPrefix.PrefixIncrement) {
  451.                         il.Emit(OpCodes.Dup);
  452.                         il.Emit(OpCodes.Stloc, result);
  453.                     }
  454.                 }
  455.                 Convert.Emit(this, il, Typeob.Object, type);
  456.                 this.operand.TranslateToILSet(il);
  457.                 if (rtype != Typeob.Void) {
  458.                     il.Emit(OpCodes.Ldloc, result);
  459.                     Convert.Emit(this, il, Typeob.Object, rtype);
  460.                 }
  461.             }
  462.         }
  463.        
  464.         internal override void TranslateToILInitializer(ILGenerator il)
  465.         {
  466.             IReflect rtype = this.InferType(null);
  467.             this.operand.TranslateToILInitializer(il);
  468.             if (rtype != Typeob.Object)
  469.                 return;
  470.             this.metaData = il.DeclareLocal(Typeob.PostOrPrefixOperator);
  471.             ConstantWrapper.TranslateToILInt(il, (int)this.operatorTok);
  472.             il.Emit(OpCodes.Newobj, CompilerGlobals.postOrPrefixConstructor);
  473.             il.Emit(OpCodes.Stloc, (LocalBuilder)this.metaData);
  474.         }
  475.     }
  476. }

Developer Fusion