[sgen] Reenable gc-altstack test
[mono.git] / mcs / class / dlr / Runtime / Microsoft.Dynamic / Ast / ConstantExpression.cs
1 /* ****************************************************************************
2  *
3  * Copyright (c) Microsoft Corporation. 
4  *
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.
10  *
11  * You must not remove this notice, or any other, from this software.
12  *
13  *
14  * ***************************************************************************/
15
16 #if FEATURE_CORE_DLR
17 using System.Linq.Expressions;
18 #else
19 using Microsoft.Scripting.Ast;
20 #endif
21
22 #if FEATURE_NUMERICS
23 using BigInt = System.Numerics.BigInteger;
24 using Complex = System.Numerics.Complex;
25 #endif
26
27 using System;
28 using System.Reflection;
29 using Microsoft.Scripting.Generation;
30 using Microsoft.Scripting.Math;
31 using Microsoft.Scripting.Utils;
32
33 namespace Microsoft.Scripting.Ast {
34     [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1724:TypeNamesShouldNotMatchNamespaces")]
35     public static partial class Utils {
36         private static readonly ConstantExpression TrueLiteral = Expression.Constant(true, typeof(bool));
37         private static readonly ConstantExpression FalseLiteral = Expression.Constant(false, typeof(bool));
38         private static readonly ConstantExpression NullLiteral = Expression.Constant(null, typeof(object));
39         private static readonly ConstantExpression EmptyStringLiteral = Expression.Constant(String.Empty, typeof(string));
40         private static readonly ConstantExpression[] IntCache = new ConstantExpression[100];
41
42         /// <summary>
43         /// Wraps the given value in a WeakReference and returns a tree that will retrieve
44         /// the value from the WeakReference.
45         /// </summary>
46         public static MemberExpression WeakConstant(object value) {
47             System.Diagnostics.Debug.Assert(!(value is Expression));
48             return Expression.Property(
49                 Constant(new WeakReference(value)),
50                 typeof(WeakReference).GetDeclaredProperty("Target")
51             );
52         }
53
54         public static ConstantExpression Constant(object value, Type type) {
55             return Expression.Constant(value, type);
56         }
57
58         // The helper API should return ConstantExpression after SymbolConstantExpression goes away
59         public static Expression Constant(object value) {
60             if (value == null) {
61                 return NullLiteral;
62             }
63
64 #if !MONO_INTERPRETER
65             BigInteger bi = value as BigInteger;
66             if ((object)bi != null) {
67                 return BigIntegerConstant(bi);
68 #endif
69
70 #if FEATURE_NUMERICS
71             if (value is BigInt)
72                 return BigIntConstant((BigInt)value);
73             if (value is Complex)
74                 return ComplexConstant((Complex)value);
75 #endif
76
77 #if !MONO_INTERPRETER
78             if (value is Complex64)
79                 return Complex64Constant((Complex64)value);
80 #endif
81             if (value is Type) {
82                 return Expression.Constant(value, typeof(Type));
83             } else if (value is ConstructorInfo) {
84                 return Expression.Constant(value, typeof(ConstructorInfo));
85             } else if (value is EventInfo) {
86                 return Expression.Constant(value, typeof(EventInfo));
87             } else if (value is FieldInfo) {
88                 return Expression.Constant(value, typeof(FieldInfo));
89             } else if (value is MethodInfo) {
90                 return Expression.Constant(value, typeof(MethodInfo));
91             } else if (value is PropertyInfo) {
92                 return Expression.Constant(value, typeof(PropertyInfo));
93             } else {
94                 Type t = value.GetType();
95                 if (!t.GetTypeInfo().IsEnum) {
96                     switch (t.GetTypeCode()) {
97                         case TypeCode.Boolean:
98                             return (bool)value ? TrueLiteral : FalseLiteral;
99                         case TypeCode.Int32:
100                             int x = (int)value;
101                             int cacheIndex = x + 2;
102                             if (cacheIndex >= 0 && cacheIndex < IntCache.Length) {
103                                 ConstantExpression res;
104                                 if ((res = IntCache[cacheIndex]) == null) {
105                                     IntCache[cacheIndex] = res = Constant(x, typeof(int));
106                                 }
107                                 return res;
108                             }
109                             break;
110                         case TypeCode.String:
111                             if (String.IsNullOrEmpty((string)value)) {
112                                 return EmptyStringLiteral;
113                             }
114                             break;
115                     }
116                 }
117                 return Expression.Constant(value);
118             }
119         }
120
121 #if !MONO_INTERPRETER
122         private static Expression BigIntegerConstant(BigInteger value) {
123             int ival;
124             if (value.AsInt32(out ival)) {
125                 return Expression.Call(
126                     new Func<int, BigInteger>(BigInteger.Create).GetMethodInfo(),
127                     Constant(ival)
128                 );
129             }
130
131             long lval;
132             if (value.AsInt64(out lval)) {
133                 return Expression.Call(
134                     new Func<long, BigInteger>(BigInteger.Create).GetMethodInfo(),
135                     Constant(lval)
136                 );
137             }
138
139 #if !FEATURE_NUMERICS
140             return Expression.Call(
141                 new Func<int, uint[], BigInteger>(CompilerHelpers.CreateBigInteger).Method,
142                 Constant((int)value.Sign),
143                 CreateArray<uint>(value.GetWords())
144             );
145 #else
146             return Expression.Call(
147                 new Func<bool, byte[], BigInteger>(CompilerHelpers.CreateBigInteger).GetMethodInfo(),
148                 Constant(value.Sign < 0),
149                 CreateArray<byte>(value.Abs().ToByteArray())
150             );
151         }
152
153         private static Expression BigIntConstant(BigInt value) {
154             int ival;
155             if (value.AsInt32(out ival)) {
156                 return Expression.Call(
157                     new Func<int, BigInt>(CompilerHelpers.CreateBigInt).GetMethodInfo(),
158                     Constant(ival)
159                 );
160             }
161
162             long lval;
163             if (value.AsInt64(out lval)) {
164                 return Expression.Call(
165                     new Func<long, BigInt>(CompilerHelpers.CreateBigInt).GetMethodInfo(),
166                     Constant(lval)
167                 );
168             }
169
170             return Expression.Call(
171                 new Func<bool, byte[], BigInt>(CompilerHelpers.CreateBigInt).GetMethodInfo(),
172                 Constant(value.Sign < 0),
173                 CreateArray<byte>(value.Abs().ToByteArray())
174             );
175 #endif
176         }
177 #endif
178         private static Expression CreateArray<T>(T[] array) {
179             // TODO: could we use blobs?
180             Expression[] init = new Expression[array.Length];
181             for (int i = 0; i < init.Length; i++) {
182                 init[i] = Constant(array[i]);
183             }
184             return Expression.NewArrayInit(typeof(T), init);
185         }
186
187 #if FEATURE_NUMERICS
188         private static Expression ComplexConstant(Complex value) {
189             if (value.Real != 0.0) {
190                 if (value.Imaginary() != 0.0) {
191                     return Expression.Call(
192                         new Func<double, double, Complex>(MathUtils.MakeComplex).GetMethodInfo(),
193                         Constant(value.Real),
194                         Constant(value.Imaginary())
195                     );
196                 } else {
197                     return Expression.Call(
198                         new Func<double, Complex>(MathUtils.MakeReal).GetMethodInfo(),
199                         Constant(value.Real)
200                     );
201                 }
202             } else {
203                 return Expression.Call(
204                     new Func<double, Complex>(MathUtils.MakeImaginary).GetMethodInfo(),
205                     Constant(value.Imaginary())
206                 );
207             }
208         }
209 #endif
210
211 #if !MONO_INTERPRETER
212         private static Expression Complex64Constant(Complex64 value) {
213             if (value.Real != 0.0) {
214                 if (value.Imag != 0.0) {
215                     return Expression.Call(
216                         new Func<double, double, Complex64>(Complex64.Make).GetMethodInfo(),
217                         Constant(value.Real),
218                         Constant(value.Imag)
219                     );
220                 } else {
221                     return Expression.Call(
222                         new Func<double, Complex64>(Complex64.MakeReal).GetMethodInfo(),
223                         Constant(value.Real)
224                     );
225                 }
226             } else {
227                 return Expression.Call(
228                     new Func<double, Complex64>(Complex64.MakeImaginary).GetMethodInfo(),
229                     Constant(value.Imag)
230                 );
231             }
232         }
233 #endif
234     }
235 }