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

  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. /* This class is used to wrap up compile-time constants in AST nodes.
  16.   For the most part, this means enums, primitives, strings, types and name spaces.
  17.   However, it can also be used to wrap the builtin objects when in Fast mode.
  18.   Addditionally null (Empty.Value), DBNull.Value and Missing.Value can be wrapped.
  19.  
  20.   No other kind of value should be wrapped by this class.
  21. */
  22. namespace Microsoft.JScript
  23. {
  24.    
  25.     using System;
  26.     using System.Reflection;
  27.     using System.Reflection.Emit;
  28.     using System.Globalization;
  29.    
  30.     internal class ConstantWrapper : AST
  31.     {
  32.         internal object value;
  33.         internal bool isNumericLiteral;
  34.        
  35.         internal ConstantWrapper(object value, Context context) : base(context)
  36.         {
  37.             if (value is ConcatString)
  38.                 value = value.ToString();
  39.             this.value = value;
  40.             this.isNumericLiteral = false;
  41.         }
  42.        
  43.         internal override object Evaluate()
  44.         {
  45.             return this.value;
  46.         }
  47.        
  48.         internal override IReflect InferType(JSField inference_target)
  49.         {
  50.             if (this.value == null || this.value is DBNull)
  51.                 return Typeob.Object;
  52.             else if (this.value is ClassScope || this.value is TypedArray)
  53.                 return Typeob.Type;
  54.             else if (this.value is EnumWrapper)
  55.                 return ((EnumWrapper)this.value).classScopeOrType;
  56.             else
  57.                 return Globals.TypeRefs.ToReferenceContext(this.value.GetType());
  58.         }
  59.        
  60.         internal bool IsAssignableTo(Type rtype)
  61.         {
  62.             try {
  63.                 Convert.CoerceT(this.value, rtype, false);
  64.                 return true;
  65.             }
  66.             catch {
  67.                 return false;
  68.             }
  69.         }
  70.        
  71.         internal override AST PartiallyEvaluate()
  72.         {
  73.             return this;
  74.         }
  75.        
  76.         public override string ToString()
  77.         {
  78.             return this.value.ToString();
  79.         }
  80.        
  81.         internal override void TranslateToIL(ILGenerator il, Type rtype)
  82.         {
  83.             if (rtype == Typeob.Void)
  84.                 return;
  85.             object val = this.value;
  86.             if (val is EnumWrapper && rtype != Typeob.Object && rtype != Typeob.String)
  87.                 val = ((EnumWrapper)val).value;
  88.             if (this.isNumericLiteral && (rtype == Typeob.Decimal || rtype == Typeob.Int64 || rtype == Typeob.UInt64 || rtype == Typeob.Single))
  89.                 val = this.context.GetCode();
  90.             if (!(rtype is TypeBuilder)) {
  91.                 try {
  92.                     val = Convert.CoerceT(val, rtype);
  93.                 }
  94.                 catch {
  95.                 }
  96.             }
  97.             this.TranslateToIL(il, val, rtype);
  98.         }
  99.        
  100.         private void TranslateToIL(ILGenerator il, object val, Type rtype)
  101.         {
  102.             IConvertible ic = Convert.GetIConvertible(val);
  103.             switch (Convert.GetTypeCode(val, ic)) {
  104.                 case TypeCode.Empty:
  105.                     il.Emit(OpCodes.Ldnull);
  106.                     if (rtype.IsValueType)
  107.                         Convert.Emit(this, il, Typeob.Object, rtype);
  108.                     return;
  109.                 case TypeCode.Object:
  110.                     break;
  111.                 case TypeCode.DBNull:
  112.                     il.Emit(OpCodes.Ldsfld, Typeob.Null.GetField("Value"));
  113.                     Convert.Emit(this, il, Typeob.Null, rtype);
  114.                     return;
  115.                 case TypeCode.Boolean:
  116.                     ConstantWrapper.TranslateToILInt(il, ic.ToInt32(null));
  117.                     Convert.Emit(this, il, Typeob.Boolean, rtype);
  118.                     return;
  119.                 case TypeCode.Char:
  120.                 case TypeCode.SByte:
  121.                 case TypeCode.Byte:
  122.                 case TypeCode.Int16:
  123.                 case TypeCode.UInt16:
  124.                 case TypeCode.Int32:
  125.                     ConstantWrapper.TranslateToILInt(il, ic.ToInt32(null));
  126.                     if (rtype.IsEnum)
  127.                         return;
  128.                     if (val is EnumWrapper)
  129.                         Convert.Emit(this, il, ((EnumWrapper)val).type, rtype);
  130.                     else
  131.                         Convert.Emit(this, il, Globals.TypeRefs.ToReferenceContext(val.GetType()), rtype);
  132.                     return;
  133.                 case TypeCode.UInt32:
  134.                     ConstantWrapper.TranslateToILInt(il, (int)ic.ToUInt32(null));
  135.                     if (rtype.IsEnum)
  136.                         return;
  137.                     if (val is EnumWrapper)
  138.                         Convert.Emit(this, il, ((EnumWrapper)val).type, rtype);
  139.                     else
  140.                         Convert.Emit(this, il, Typeob.UInt32, rtype);
  141.                     return;
  142.                 case TypeCode.Int64:
  143.                     long l = ic.ToInt64(null);
  144.                     if (Int32.MinValue <= l && l <= Int32.MaxValue) {
  145.                         ConstantWrapper.TranslateToILInt(il, (int)l);
  146.                         il.Emit(OpCodes.Conv_I8);
  147.                     }
  148.                     else
  149.                         il.Emit(OpCodes.Ldc_I8, l);
  150.                     if (rtype.IsEnum)
  151.                         return;
  152.                     if (val is EnumWrapper)
  153.                         Convert.Emit(this, il, ((EnumWrapper)val).type, rtype);
  154.                     else
  155.                         Convert.Emit(this, il, Typeob.Int64, rtype);
  156.                     return;
  157.                 case TypeCode.UInt64:
  158.                     ulong ul = ic.ToUInt64(null);
  159.                     if (ul <= Int32.MaxValue) {
  160.                         ConstantWrapper.TranslateToILInt(il, (int)ul);
  161.                         il.Emit(OpCodes.Conv_I8);
  162.                     }
  163.                     else
  164.                         il.Emit(OpCodes.Ldc_I8, (long)ul);
  165.                     if (rtype.IsEnum)
  166.                         return;
  167.                     if (val is EnumWrapper)
  168.                         Convert.Emit(this, il, ((EnumWrapper)val).type, rtype);
  169.                     else
  170.                         Convert.Emit(this, il, Typeob.UInt64, rtype);
  171.                     return;
  172.                 case TypeCode.Single:
  173.                     float f = ic.ToSingle(null);
  174.                     if (f == f && (f != 0 || !Single.IsNegativeInfinity(1 / f))) {
  175.                         int i = (int)Runtime.DoubleToInt64(f);
  176.                         if (-128 <= i && i <= 127 && f == (float)i) {
  177.                             ConstantWrapper.TranslateToILInt(il, i);
  178.                             il.Emit(OpCodes.Conv_R4);
  179.                         }
  180.                         else
  181.                             il.Emit(OpCodes.Ldc_R4, f);
  182.                     }
  183.                     else
  184.                         il.Emit(OpCodes.Ldc_R4, f);
  185.                     Convert.Emit(this, il, Typeob.Single, rtype);
  186.                     return;
  187.                 case TypeCode.Double:
  188.                     double d = ic.ToDouble(null);
  189.                     if (d == d && (d != 0 || !Double.IsNegativeInfinity(1 / d))) {
  190.                         int i = (int)Runtime.DoubleToInt64(d);
  191.                         if (-128 <= i && i <= 127 && d == (double)i) {
  192.                             ConstantWrapper.TranslateToILInt(il, i);
  193.                             il.Emit(OpCodes.Conv_R8);
  194.                         }
  195.                         else
  196.                             il.Emit(OpCodes.Ldc_R8, d);
  197.                     }
  198.                     else
  199.                         il.Emit(OpCodes.Ldc_R8, d);
  200.                     Convert.Emit(this, il, Typeob.Double, rtype);
  201.                     return;
  202.                 case TypeCode.Decimal:
  203.                     int[] bits = Decimal.GetBits(ic.ToDecimal(null));
  204.                     ConstantWrapper.TranslateToILInt(il, bits[0]);
  205.                     ConstantWrapper.TranslateToILInt(il, bits[1]);
  206.                     ConstantWrapper.TranslateToILInt(il, bits[2]);
  207.                     il.Emit(bits[3] < 0 ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
  208.                     //bool isNegative
  209.                     ConstantWrapper.TranslateToILInt(il, (bits[3] & 2147483647) >> 16);
  210.                     il.Emit(OpCodes.Newobj, CompilerGlobals.decimalConstructor);
  211.                     Convert.Emit(this, il, Typeob.Decimal, rtype);
  212.                     return;
  213.                 case TypeCode.DateTime:
  214.                     l = ic.ToDateTime(null).Ticks;
  215.                     il.Emit(OpCodes.Ldc_I8, l);
  216.                     Convert.Emit(this, il, Typeob.Int64, rtype);
  217.                     return;
  218.                 case TypeCode.String:
  219.                     string str = ic.ToString(null);
  220.                     if (rtype == Typeob.Char && str.Length == 1) {
  221.                         ConstantWrapper.TranslateToILInt(il, (int)str[0]);
  222.                         return;
  223.                     }
  224.                     il.Emit(OpCodes.Ldstr, str);
  225.                     Convert.Emit(this, il, Typeob.String, rtype);
  226.                     return;
  227.             }
  228.             if (val is Enum) {
  229.                 if (rtype == Typeob.String)
  230.                     this.TranslateToIL(il, val.ToString(), rtype);
  231.                 else if (rtype.IsPrimitive)
  232.                     this.TranslateToIL(il, System.Convert.ChangeType(val, Enum.GetUnderlyingType(Globals.TypeRefs.ToReferenceContext(val.GetType())), CultureInfo.InvariantCulture), rtype);
  233.                 else {
  234.                     Type et = Globals.TypeRefs.ToReferenceContext(val.GetType());
  235.                     Type ut = Enum.GetUnderlyingType(et);
  236.                     this.TranslateToIL(il, System.Convert.ChangeType(val, ut, CultureInfo.InvariantCulture), ut);
  237.                     il.Emit(OpCodes.Box, et);
  238.                     Convert.Emit(this, il, Typeob.Object, rtype);
  239.                 }
  240.                 return;
  241.             }
  242.             if (val is EnumWrapper) {
  243.                 if (rtype == Typeob.String)
  244.                     this.TranslateToIL(il, val.ToString(), rtype);
  245.                 else if (rtype.IsPrimitive)
  246.                     this.TranslateToIL(il, ((EnumWrapper)val).ToNumericValue(), rtype);
  247.                 else {
  248.                     Type et = ((EnumWrapper)val).type;
  249.                     Type ut = Globals.TypeRefs.ToReferenceContext(((EnumWrapper)val).value.GetType());
  250.                     this.TranslateToIL(il, ((EnumWrapper)val).value, ut);
  251.                     il.Emit(OpCodes.Box, et);
  252.                     Convert.Emit(this, il, Typeob.Object, rtype);
  253.                 }
  254.                 return;
  255.             }
  256.             if (val is Type) {
  257.                 il.Emit(OpCodes.Ldtoken, (Type)val);
  258.                 il.Emit(OpCodes.Call, CompilerGlobals.getTypeFromHandleMethod);
  259.                 Convert.Emit(this, il, Typeob.Type, rtype);
  260.             }
  261.             else if (val is Namespace) {
  262.                 il.Emit(OpCodes.Ldstr, ((Namespace)val).Name);
  263.                 this.EmitILToLoadEngine(il);
  264.                 il.Emit(OpCodes.Call, CompilerGlobals.getNamespaceMethod);
  265.                 Convert.Emit(this, il, Typeob.Namespace, rtype);
  266.             }
  267.             else if (val is ClassScope) {
  268.                 il.Emit(OpCodes.Ldtoken, ((ClassScope)val).GetTypeBuilderOrEnumBuilder());
  269.                 il.Emit(OpCodes.Call, CompilerGlobals.getTypeFromHandleMethod);
  270.                 Convert.Emit(this, il, Typeob.Type, rtype);
  271.             }
  272.             else if (val is TypedArray) {
  273.                 il.Emit(OpCodes.Ldtoken, Convert.ToType((TypedArray)val));
  274.                 il.Emit(OpCodes.Call, CompilerGlobals.getTypeFromHandleMethod);
  275.                 Convert.Emit(this, il, Typeob.Type, rtype);
  276.             }
  277.             else if (val is NumberObject) {
  278.                 this.TranslateToIL(il, ((NumberObject)val).value, Typeob.Object);
  279.                 this.EmitILToLoadEngine(il);
  280.                 il.Emit(OpCodes.Call, CompilerGlobals.toObjectMethod);
  281.                 Convert.Emit(this, il, Typeob.NumberObject, rtype);
  282.             }
  283.             else if (val is StringObject) {
  284.                 il.Emit(OpCodes.Ldstr, ((StringObject)val).value);
  285.                 this.EmitILToLoadEngine(il);
  286.                 il.Emit(OpCodes.Call, CompilerGlobals.toObjectMethod);
  287.                 Convert.Emit(this, il, Typeob.StringObject, rtype);
  288.             }
  289.             else if (val is BooleanObject) {
  290.                 il.Emit(((BooleanObject)val).value ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
  291.                 il.Emit(OpCodes.Box, Typeob.Boolean);
  292.                 this.EmitILToLoadEngine(il);
  293.                 il.Emit(OpCodes.Call, CompilerGlobals.toObjectMethod);
  294.                 Convert.Emit(this, il, Typeob.BooleanObject, rtype);
  295.             }
  296.             else if (val is ActiveXObjectConstructor) {
  297.                 il.Emit(OpCodes.Call, Typeob.GlobalObject.GetProperty("ActiveXObject").GetGetMethod());
  298.                 Convert.Emit(this, il, Typeob.ScriptFunction, rtype);
  299.             }
  300.             else if (val is ArrayConstructor) {
  301.                 il.Emit(OpCodes.Call, Typeob.GlobalObject.GetProperty("Array").GetGetMethod());
  302.                 Convert.Emit(this, il, Typeob.ScriptFunction, rtype);
  303.             }
  304.             else if (val is BooleanConstructor) {
  305.                 il.Emit(OpCodes.Call, Typeob.GlobalObject.GetProperty("Boolean").GetGetMethod());
  306.                 Convert.Emit(this, il, Typeob.ScriptFunction, rtype);
  307.             }
  308.             else if (val is DateConstructor) {
  309.                 il.Emit(OpCodes.Call, Typeob.GlobalObject.GetProperty("Date").GetGetMethod());
  310.                 Convert.Emit(this, il, Typeob.ScriptFunction, rtype);
  311.             }
  312.             else if (val is EnumeratorConstructor) {
  313.                 il.Emit(OpCodes.Call, Typeob.GlobalObject.GetProperty("Enumerator").GetGetMethod());
  314.                 Convert.Emit(this, il, Typeob.ScriptFunction, rtype);
  315.             }
  316.             else if (val is ErrorConstructor) {
  317.                 ErrorConstructor error = (ErrorConstructor)val;
  318.                 if (error == ErrorConstructor.evalOb)
  319.                     il.Emit(OpCodes.Call, Typeob.GlobalObject.GetProperty("EvalError").GetGetMethod());
  320.                 else if (error == ErrorConstructor.rangeOb)
  321.                     il.Emit(OpCodes.Call, Typeob.GlobalObject.GetProperty("RangeError").GetGetMethod());
  322.                 else if (error == ErrorConstructor.referenceOb)
  323.                     il.Emit(OpCodes.Call, Typeob.GlobalObject.GetProperty("ReferenceError").GetGetMethod());
  324.                 else if (error == ErrorConstructor.syntaxOb)
  325.                     il.Emit(OpCodes.Call, Typeob.GlobalObject.GetProperty("SyntaxError").GetGetMethod());
  326.                 else if (error == ErrorConstructor.typeOb)
  327.                     il.Emit(OpCodes.Call, Typeob.GlobalObject.GetProperty("TypeError").GetGetMethod());
  328.                 else if (error == ErrorConstructor.uriOb)
  329.                     il.Emit(OpCodes.Call, Typeob.GlobalObject.GetProperty("URIError").GetGetMethod());
  330.                 else
  331.                     il.Emit(OpCodes.Call, Typeob.GlobalObject.GetProperty("Error").GetGetMethod());
  332.                 Convert.Emit(this, il, Typeob.ScriptFunction, rtype);
  333.             }
  334.             else if (val is FunctionConstructor) {
  335.                 il.Emit(OpCodes.Call, Typeob.GlobalObject.GetProperty("Function").GetGetMethod());
  336.                 Convert.Emit(this, il, Typeob.ScriptFunction, rtype);
  337.             }
  338.             else if (val is MathObject) {
  339.                 il.Emit(OpCodes.Call, Typeob.GlobalObject.GetProperty("Math").GetGetMethod());
  340.                 Convert.Emit(this, il, Typeob.JSObject, rtype);
  341.             }
  342.             else if (val is NumberConstructor) {
  343.                 il.Emit(OpCodes.Call, Typeob.GlobalObject.GetProperty("Number").GetGetMethod());
  344.                 Convert.Emit(this, il, Typeob.ScriptFunction, rtype);
  345.             }
  346.             else if (val is ObjectConstructor) {
  347.                 il.Emit(OpCodes.Call, Typeob.GlobalObject.GetProperty("Object").GetGetMethod());
  348.                 Convert.Emit(this, il, Typeob.ScriptFunction, rtype);
  349.             }
  350.             else if (val is RegExpConstructor) {
  351.                 il.Emit(OpCodes.Call, Typeob.GlobalObject.GetProperty("RegExp").GetGetMethod());
  352.                 Convert.Emit(this, il, Typeob.ScriptFunction, rtype);
  353.             }
  354.             else if (val is StringConstructor) {
  355.                 il.Emit(OpCodes.Call, Typeob.GlobalObject.GetProperty("String").GetGetMethod());
  356.                 Convert.Emit(this, il, Typeob.ScriptFunction, rtype);
  357.             }
  358.             else if (val is VBArrayConstructor) {
  359.                 il.Emit(OpCodes.Call, Typeob.GlobalObject.GetProperty("VBArray").GetGetMethod());
  360.                 Convert.Emit(this, il, Typeob.ScriptFunction, rtype);
  361.             }
  362.             else if (val is IntPtr) {
  363.                 il.Emit(OpCodes.Ldc_I8, (long)(IntPtr)val);
  364.                 il.Emit(OpCodes.Conv_I);
  365.                 Convert.Emit(this, il, Typeob.IntPtr, rtype);
  366.             }
  367.             else if (val is UIntPtr) {
  368.                 il.Emit(OpCodes.Ldc_I8, (long)(UIntPtr)val);
  369.                 il.Emit(OpCodes.Conv_U);
  370.                 Convert.Emit(this, il, Typeob.UIntPtr, rtype);
  371.             }
  372.             else if (val is Missing) {
  373.                 il.Emit(OpCodes.Ldsfld, CompilerGlobals.missingField);
  374.                 Convert.Emit(this, il, Typeob.Object, rtype);
  375.             }
  376.             else if (val is System.Reflection.Missing) {
  377.                 if (rtype.IsPrimitive)
  378.                     this.TranslateToIL(il, Double.NaN, rtype);
  379.                 else if (rtype != Typeob.Object && !rtype.IsValueType)
  380.                     il.Emit(OpCodes.Ldnull);
  381.                 else {
  382.                     il.Emit(OpCodes.Ldsfld, CompilerGlobals.systemReflectionMissingField);
  383.                     Convert.Emit(this, il, Typeob.Object, rtype);
  384.                 }
  385.             }
  386.             else if (val != this.value)
  387.                 this.TranslateToIL(il, this.value, rtype);
  388.             else
  389.                 //Value was coerced to some type we have no compile time knowlegde of
  390.                 throw new JScriptException(JSError.InternalError, this.context);
  391.             //It should not be possible to wrap any other kind of object
  392.         }
  393.        
  394.         static internal void TranslateToILInt(ILGenerator il, int i)
  395.         {
  396.             switch (i) {
  397.                 case -1:
  398.                     il.Emit(OpCodes.Ldc_I4_M1);
  399.                     break;
  400.                 case 0:
  401.                     il.Emit(OpCodes.Ldc_I4_0);
  402.                     break;
  403.                 case 1:
  404.                     il.Emit(OpCodes.Ldc_I4_1);
  405.                     break;
  406.                 case 2:
  407.                     il.Emit(OpCodes.Ldc_I4_2);
  408.                     break;
  409.                 case 3:
  410.                     il.Emit(OpCodes.Ldc_I4_3);
  411.                     break;
  412.                 case 4:
  413.                     il.Emit(OpCodes.Ldc_I4_4);
  414.                     break;
  415.                 case 5:
  416.                     il.Emit(OpCodes.Ldc_I4_5);
  417.                     break;
  418.                 case 6:
  419.                     il.Emit(OpCodes.Ldc_I4_6);
  420.                     break;
  421.                 case 7:
  422.                     il.Emit(OpCodes.Ldc_I4_7);
  423.                     break;
  424.                 case 8:
  425.                     il.Emit(OpCodes.Ldc_I4_8);
  426.                     break;
  427.                 default:
  428.                     if (-128 <= i && i <= 127)
  429.                         il.Emit(OpCodes.Ldc_I4_S, (sbyte)i);
  430.                     else
  431.                         il.Emit(OpCodes.Ldc_I4, i);
  432.                     break;
  433.             }
  434.         }
  435.        
  436.         internal override void TranslateToILInitializer(ILGenerator il)
  437.         {
  438.         }
  439.        
  440.     }
  441. }

Developer Fusion