Merge branch 'BigIntegerParse'
[mono.git] / mcs / class / dlr / Runtime / Microsoft.Dynamic / Runtime / ScriptingRuntimeHelpers.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 using System;
17 using System.Collections;
18 using System.Collections.Generic;
19 using System.Diagnostics;
20 using System.Reflection;
21 using System.Runtime.CompilerServices;
22 using Microsoft.Scripting.Actions;
23 using Microsoft.Scripting.Generation;
24 using Microsoft.Scripting.Utils;
25 using Microsoft.Scripting.Interpreter;
26
27 namespace Microsoft.Scripting.Runtime {
28     /// <summary>
29     /// These are some generally useful helper methods. Currently the only methods are those to
30     /// cached boxed representations of commonly used primitive types so that they can be shared.
31     /// This is useful to most dynamic languages that use object as a universal type.
32     /// 
33     /// The methods in RuntimeHelepers are caleld by the generated code. From here the methods may
34     /// dispatch to other parts of the runtime to get bulk of the work done, but the entry points
35     /// should be here.
36     /// </summary>
37     [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling")]
38     public static partial class ScriptingRuntimeHelpers {
39         private const int MIN_CACHE = -100;
40         private const int MAX_CACHE = 1000;
41         private static readonly object[] cache = MakeCache();
42
43         /// <summary>
44         /// A singleton boxed boolean true.
45         /// </summary>
46         public static readonly object True = true;
47
48         /// <summary>
49         ///A singleton boxed boolean false.
50         /// </summary>
51         public static readonly object False = false;
52
53         internal static readonly MethodInfo BooleanToObjectMethod = typeof(ScriptingRuntimeHelpers).GetMethod("BooleanToObject");
54         internal static readonly MethodInfo Int32ToObjectMethod = typeof(ScriptingRuntimeHelpers).GetMethod("Int32ToObject");
55
56         private static object[] MakeCache() {
57             object[] result = new object[MAX_CACHE - MIN_CACHE];
58
59             for (int i = 0; i < result.Length; i++) {
60                 result[i] = (object)(i + MIN_CACHE);
61             }
62
63             return result;
64         }
65
66 #if DEBUG
67         public static void NoteException(Exception e) {
68             PerfTrack.NoteEvent(PerfTrack.Categories.Exceptions, "LightEH Missed: " + e.GetType());
69         }
70 #endif
71
72         /// <summary>
73         /// Gets a singleton boxed value for the given integer if possible, otherwise boxes the integer.
74         /// </summary>
75         /// <param name="value">The value to box.</param>
76         /// <returns>The boxed value.</returns>
77         public static object Int32ToObject(Int32 value) {
78             // caches improves pystone by ~5-10% on MS .Net 1.1, this is a very integer intense app
79             // TODO: investigate if this still helps perf. There's evidence that it's harmful on
80             // .NET 3.5 and 4.0
81             if (value < MAX_CACHE && value >= MIN_CACHE) {
82                 return cache[value - MIN_CACHE];
83             }
84             return (object)value;
85         }
86
87         private static readonly string[] chars = MakeSingleCharStrings();
88
89         private static string[] MakeSingleCharStrings() {
90             string[] result = new string[255];
91
92             for (char ch = (char)0; ch < result.Length; ch++) {
93                 result[ch] = new string(ch, 1);
94             }
95
96             return result;
97         }
98
99         public static object BooleanToObject(bool value) {
100             return value ? True : False;
101         }
102
103         public static string CharToString(char ch) {
104             if (ch < 255) return chars[ch];
105             return new string(ch, 1);
106         }
107
108         internal static object GetPrimitiveDefaultValue(Type type) {
109             switch (type.GetTypeCode()) {
110                 case TypeCode.Boolean: return ScriptingRuntimeHelpers.False;
111                 case TypeCode.SByte: return default(SByte);
112                 case TypeCode.Byte: return default(Byte);
113                 case TypeCode.Char: return default(Char);
114                 case TypeCode.Int16: return default(Int16);
115                 case TypeCode.Int32: return ScriptingRuntimeHelpers.Int32ToObject(0);
116                 case TypeCode.Int64: return default(Int64);
117                 case TypeCode.UInt16: return default(UInt16);
118                 case TypeCode.UInt32: return default(UInt32);
119                 case TypeCode.UInt64: return default(UInt64);
120                 case TypeCode.Single: return default(Single);
121                 case TypeCode.Double: return default(Double);
122 #if FEATURE_DBNULL
123                 case TypeCode.DBNull: return default(DBNull);
124 #endif
125                 case TypeCode.DateTime: return default(DateTime);
126                 case TypeCode.Decimal: return default(Decimal);
127                 default: return null;
128             }
129         }
130
131         public static ArgumentTypeException SimpleTypeError(string message) {
132             return new ArgumentTypeException(message);
133         }
134
135         [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")] // TODO: fix
136         public static Exception CannotConvertError(Type toType, object value) {
137             return SimpleTypeError(String.Format("Cannot convert {0}({1}) to {2}", CompilerHelpers.GetType(value).Name, value, toType.Name));
138         }
139
140         public static Exception SimpleAttributeError(string message) {
141             //TODO: localize
142             return new MissingMemberException(message);
143         }
144
145         public static object ReadOnlyAssignError(bool field, string fieldName) {
146             if (field) {
147                 throw Error.FieldReadonly(fieldName);
148             } else {
149                 throw Error.PropertyReadonly(fieldName);
150             }
151         }
152
153         /// <summary>
154         /// Helper method to create an instance.  Work around for Silverlight where Activator.CreateInstance
155         /// is SecuritySafeCritical.
156         /// 
157         /// TODO: Why can't we just emit the right thing for default(T)?
158         /// It's always null for reference types and it's well defined for value types
159         /// </summary>
160         public static T CreateInstance<T>() {
161             return default(T);
162         }
163
164         // TODO: can't we just emit a new array?
165         public static T[] CreateArray<T>(int args) {
166             return new T[args];
167         }
168         
169         /// <summary>
170         /// EventInfo.EventHandlerType getter is marked SecuritySafeCritical in CoreCLR
171         /// This method is to get to the property without using Reflection
172         /// </summary>
173         /// <param name="eventInfo"></param>
174         /// <returns></returns>
175         public static Type GetEventHandlerType(EventInfo eventInfo) {
176             ContractUtils.RequiresNotNull(eventInfo, "eventInfo");
177             return eventInfo.EventHandlerType;
178         }
179
180         public static IList<string> GetStringMembers(IList<object> members) {
181             List<string> res = new List<string>();
182             foreach (object o in members) {
183                 string str = o as string;
184                 if (str != null) {
185                     res.Add(str);
186                 }
187             }
188             return res;
189         }
190 #if !MONO_INTERPRETER
191         [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")] // TODO: fix
192         public static void SetEvent(EventTracker eventTracker, object value) {
193             EventTracker et = value as EventTracker;
194             if (et != null) {
195                 if (et != eventTracker) {
196                     throw Error.UnexpectedEvent(eventTracker.DeclaringType.Name,
197                                                 eventTracker.Name,
198                                                 et.DeclaringType.Name,
199                                                 et.Name);
200                 }
201                 return;
202             }
203
204             BoundMemberTracker bmt = value as BoundMemberTracker;
205             if (bmt == null) {
206                 throw Error.ExpectedBoundEvent(CompilerHelpers.GetType(value).Name);
207             }
208             if (bmt.BoundTo.MemberType != TrackerTypes.Event) throw Error.ExpectedBoundEvent(bmt.BoundTo.MemberType.ToString());
209
210             if (bmt.BoundTo != eventTracker) throw Error.UnexpectedEvent(
211                 eventTracker.DeclaringType.Name,
212                 eventTracker.Name,
213                 bmt.BoundTo.DeclaringType.Name,
214                 bmt.BoundTo.Name);
215         }
216 #endif
217         // TODO: just emit this in the generated code
218         public static bool CheckDictionaryMembers(IDictionary dict, string[] names) {
219             if (dict.Count != names.Length) return false;
220
221             foreach (string name in names) {
222                 if (!dict.Contains(name)) {
223                     return false;
224                 }
225             }
226             return true;
227         }
228
229         // TODO: just emit this in the generated code
230         [Obsolete("use MakeIncorrectBoxTypeError instead")]
231         public static T IncorrectBoxType<T>(object received) {
232             throw Error.UnexpectedType("StrongBox<" + typeof(T).Name + ">", CompilerHelpers.GetType(received).Name);
233         }
234
235         public static Exception MakeIncorrectBoxTypeError(Type type, object received) {
236             return Error.UnexpectedType("StrongBox<" + type.Name + ">", CompilerHelpers.GetType(received).Name);
237         }
238         
239         /// <summary>
240         /// Provides the test to see if an interpreted call site should switch over to being compiled.
241         /// </summary>
242         public static bool InterpretedCallSiteTest(bool restrictionResult, object bindingInfo) {
243             if (restrictionResult) {
244                 CachedBindingInfo bindInfo = (CachedBindingInfo)bindingInfo;
245                 if (bindInfo.CompilationThreshold >= 0) {
246                     // still interpreting...
247                     bindInfo.CompilationThreshold--;
248                     return true;
249                 }
250 #if SILVERLIGHT
251                 if (PlatformAdaptationLayer.IsCompactFramework) {
252                     bindInfo.CompilationThreshold = Int32.MaxValue;
253                     return true;
254                 }
255 #endif
256                 return bindInfo.CheckCompiled();
257             }
258             return false;
259         }
260     }
261 }