1 /* ****************************************************************************
3 * Copyright (c) Microsoft Corporation.
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.
11 * You must not remove this notice, or any other, from this software.
14 * ***************************************************************************/
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;
27 namespace Microsoft.Scripting.Runtime {
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.
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
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();
44 /// A singleton boxed boolean true.
46 public static readonly object True = true;
49 ///A singleton boxed boolean false.
51 public static readonly object False = false;
53 internal static readonly MethodInfo BooleanToObjectMethod = typeof(ScriptingRuntimeHelpers).GetMethod("BooleanToObject");
54 internal static readonly MethodInfo Int32ToObjectMethod = typeof(ScriptingRuntimeHelpers).GetMethod("Int32ToObject");
56 private static object[] MakeCache() {
57 object[] result = new object[MAX_CACHE - MIN_CACHE];
59 for (int i = 0; i < result.Length; i++) {
60 result[i] = (object)(i + MIN_CACHE);
67 public static void NoteException(Exception e) {
68 PerfTrack.NoteEvent(PerfTrack.Categories.Exceptions, "LightEH Missed: " + e.GetType());
73 /// Gets a singleton boxed value for the given integer if possible, otherwise boxes the integer.
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
81 if (value < MAX_CACHE && value >= MIN_CACHE) {
82 return cache[value - MIN_CACHE];
87 private static readonly string[] chars = MakeSingleCharStrings();
89 private static string[] MakeSingleCharStrings() {
90 string[] result = new string[255];
92 for (char ch = (char)0; ch < result.Length; ch++) {
93 result[ch] = new string(ch, 1);
99 public static object BooleanToObject(bool value) {
100 return value ? True : False;
103 public static string CharToString(char ch) {
104 if (ch < 255) return chars[ch];
105 return new string(ch, 1);
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);
123 case TypeCode.DBNull: return default(DBNull);
125 case TypeCode.DateTime: return default(DateTime);
126 case TypeCode.Decimal: return default(Decimal);
127 default: return null;
131 public static ArgumentTypeException SimpleTypeError(string message) {
132 return new ArgumentTypeException(message);
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));
140 public static Exception SimpleAttributeError(string message) {
142 return new MissingMemberException(message);
145 public static object ReadOnlyAssignError(bool field, string fieldName) {
147 throw Error.FieldReadonly(fieldName);
149 throw Error.PropertyReadonly(fieldName);
154 /// Helper method to create an instance. Work around for Silverlight where Activator.CreateInstance
155 /// is SecuritySafeCritical.
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
160 public static T CreateInstance<T>() {
164 // TODO: can't we just emit a new array?
165 public static T[] CreateArray<T>(int args) {
170 /// EventInfo.EventHandlerType getter is marked SecuritySafeCritical in CoreCLR
171 /// This method is to get to the property without using Reflection
173 /// <param name="eventInfo"></param>
174 /// <returns></returns>
175 public static Type GetEventHandlerType(EventInfo eventInfo) {
176 ContractUtils.RequiresNotNull(eventInfo, "eventInfo");
177 return eventInfo.EventHandlerType;
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;
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;
195 if (et != eventTracker) {
196 throw Error.UnexpectedEvent(eventTracker.DeclaringType.Name,
198 et.DeclaringType.Name,
204 BoundMemberTracker bmt = value as BoundMemberTracker;
206 throw Error.ExpectedBoundEvent(CompilerHelpers.GetType(value).Name);
208 if (bmt.BoundTo.MemberType != TrackerTypes.Event) throw Error.ExpectedBoundEvent(bmt.BoundTo.MemberType.ToString());
210 if (bmt.BoundTo != eventTracker) throw Error.UnexpectedEvent(
211 eventTracker.DeclaringType.Name,
213 bmt.BoundTo.DeclaringType.Name,
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;
221 foreach (string name in names) {
222 if (!dict.Contains(name)) {
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);
235 public static Exception MakeIncorrectBoxTypeError(Type type, object received) {
236 return Error.UnexpectedType("StrongBox<" + type.Name + ">", CompilerHelpers.GetType(received).Name);
240 /// Provides the test to see if an interpreted call site should switch over to being compiled.
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--;
251 if (PlatformAdaptationLayer.IsCompactFramework) {
252 bindInfo.CompilationThreshold = Int32.MaxValue;
256 return bindInfo.CheckCompiled();