/Microsoft.Scripting/Actions/DynamicSiteHelper.cs
C# | 244 lines | 161 code | 44 blank | 39 comment | 25 complexity | 6ecfc9c313942d22a33b158032fc0670 MD5 | raw file
- /* ****************************************************************************
- *
- * Copyright (c) Microsoft Corporation.
- *
- * This source code is subject to terms and conditions of the Microsoft Public License. A
- * copy of the license can be found in the License.html file at the root of this distribution. If
- * you cannot locate the Microsoft Public License, please send an email to
- * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
- * by the terms of the Microsoft Public License.
- *
- * You must not remove this notice, or any other, from this software.
- *
- *
- * ***************************************************************************/
-
- #if CODEPLEX_40
- using System;
- #else
- using System; using Microsoft;
- #endif
- using System.Collections.Generic;
- using System.Diagnostics;
- using System.Runtime.CompilerServices;
- #if !CODEPLEX_40
- using Microsoft.Runtime.CompilerServices;
- #endif
-
- using System.Threading;
- using Microsoft.Scripting.Utils;
- using System.Reflection.Emit;
- using Microsoft.Scripting.Generation;
- using System.Reflection;
-
- namespace Microsoft.Scripting.Actions {
- // TODO: replace this class with calls to Expression.GetDelegateType
- public static class DynamicSiteHelpers {
-
- private delegate object CreateSite(CallSiteBinder binder);
-
- private const int MaximumArity = 17;
-
- private static Dictionary<ICollection<Type>, Type> _DelegateTypes;
-
- private const MethodAttributes CtorAttributes = MethodAttributes.RTSpecialName | MethodAttributes.HideBySig | MethodAttributes.Public;
- private const MethodImplAttributes ImplAttributes = MethodImplAttributes.Runtime | MethodImplAttributes.Managed;
- private const MethodAttributes InvokeAttributes = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual;
-
- private static readonly Type[] _DelegateCtorSignature = new Type[] { typeof(object), typeof(IntPtr) };
-
-
- // TODO: remove in favor of Expression.GetDelegateType
- internal static Type MakeCallSiteDelegate(params Type[] types) {
- Debug.Assert(types != null);
- return MakeDelegate(types.AddFirst(typeof(CallSite)));
- }
-
- private static Type MakeDelegate(Type[] types) {
- return GetStandardDelegateType(types) ?? MakeCustomDelegate(types);
- }
-
- public static Type GetStandardDelegateType(Type[] types) {
- ContractUtils.RequiresNotEmpty(types, "types");
-
- // Can only used predefined delegates if we have no byref types and
- // the arity is small enough to fit in Func<...> or Action<...>
- if (types.Length > MaximumArity || Any(types, t => t.IsByRef)) {
- return null;
- }
-
- Type result;
- if (types[types.Length - 1] == typeof(void)) {
- result = GetActionType(RemoveLast(types));
- } else {
- result = GetFuncType(types);
- }
- Debug.Assert(result != null);
- return result;
- }
-
- private static Type GetFuncType(Type[] types) {
- switch (types.Length) {
- #region Generated Delegate Microsoft Scripting Scripting Func Types
-
- // *** BEGIN GENERATED CODE ***
- // generated by function: gen_delegate_func from: generate_dynsites.py
-
- case 1: return typeof(Func<>).MakeGenericType(types);
- case 2: return typeof(Func<,>).MakeGenericType(types);
- case 3: return typeof(Func<,,>).MakeGenericType(types);
- case 4: return typeof(Func<,,,>).MakeGenericType(types);
- case 5: return typeof(Func<,,,,>).MakeGenericType(types);
- case 6: return typeof(Func<,,,,,>).MakeGenericType(types);
- case 7: return typeof(Func<,,,,,,>).MakeGenericType(types);
- case 8: return typeof(Func<,,,,,,,>).MakeGenericType(types);
- case 9: return typeof(Func<,,,,,,,,>).MakeGenericType(types);
- case 10: return typeof(Func<,,,,,,,,,>).MakeGenericType(types);
- case 11: return typeof(Func<,,,,,,,,,,>).MakeGenericType(types);
- case 12: return typeof(Func<,,,,,,,,,,,>).MakeGenericType(types);
- case 13: return typeof(Func<,,,,,,,,,,,,>).MakeGenericType(types);
- case 14: return typeof(Func<,,,,,,,,,,,,,>).MakeGenericType(types);
- case 15: return typeof(Func<,,,,,,,,,,,,,,>).MakeGenericType(types);
- case 16: return typeof(Func<,,,,,,,,,,,,,,,>).MakeGenericType(types);
- case 17: return typeof(Func<,,,,,,,,,,,,,,,,>).MakeGenericType(types);
-
- // *** END GENERATED CODE ***
-
- #endregion
-
- default: return null;
- }
- }
-
- private static Type GetActionType(Type[] types) {
- switch (types.Length) {
- case 0: return typeof(Action);
-
- #region Generated Delegate Microsoft Scripting Action Types
-
- // *** BEGIN GENERATED CODE ***
- // generated by function: gen_delegate_action from: generate_dynsites.py
-
- case 1: return typeof(Action<>).MakeGenericType(types);
- case 2: return typeof(Action<,>).MakeGenericType(types);
- case 3: return typeof(Action<,,>).MakeGenericType(types);
- case 4: return typeof(Action<,,,>).MakeGenericType(types);
- case 5: return typeof(Action<,,,,>).MakeGenericType(types);
- case 6: return typeof(Action<,,,,,>).MakeGenericType(types);
- case 7: return typeof(Action<,,,,,,>).MakeGenericType(types);
- case 8: return typeof(Action<,,,,,,,>).MakeGenericType(types);
- case 9: return typeof(Action<,,,,,,,,>).MakeGenericType(types);
- case 10: return typeof(Action<,,,,,,,,,>).MakeGenericType(types);
- case 11: return typeof(Action<,,,,,,,,,,>).MakeGenericType(types);
- case 12: return typeof(Action<,,,,,,,,,,,>).MakeGenericType(types);
- case 13: return typeof(Action<,,,,,,,,,,,,>).MakeGenericType(types);
- case 14: return typeof(Action<,,,,,,,,,,,,,>).MakeGenericType(types);
- case 15: return typeof(Action<,,,,,,,,,,,,,,>).MakeGenericType(types);
- case 16: return typeof(Action<,,,,,,,,,,,,,,,>).MakeGenericType(types);
-
- // *** END GENERATED CODE ***
-
- #endregion
- default: return null;
- }
- }
-
- private static T[] AddFirst<T>(this IList<T> list, T item) {
- T[] res = new T[list.Count + 1];
- res[0] = item;
- list.CopyTo(res, 1);
- return res;
- }
-
- private static bool Any<T>(this IEnumerable<T> source, Func<T, bool> predicate) {
- foreach (T element in source) {
- if (predicate(element)) {
- return true;
- }
- }
- return false;
- }
-
- private static T[] RemoveLast<T>(this T[] array) {
- T[] result = new T[array.Length - 1];
- Array.Copy(array, 0, result, 0, result.Length);
- return result;
- }
-
- private static Type MakeCustomDelegate(Type[] types) {
- if (_DelegateTypes == null) {
- Interlocked.CompareExchange(
- ref _DelegateTypes,
- new Dictionary<ICollection<Type>, Type>(ListEqualityComparer<Type>.Instance),
- null
- );
- }
-
- bool found;
- Type type;
-
- //
- // LOCK to retrieve the delegate type, if any
- //
-
- lock (_DelegateTypes) {
- found = _DelegateTypes.TryGetValue(types, out type);
- }
-
- if (!found && type != null) {
- return type;
- }
-
- //
- // Create new delegate type
- //
-
- type = MakeNewCustomDelegate(types);
-
- //
- // LOCK to insert new delegate into the cache. If we already have one (racing threads), use the one from the cache
- //
-
- lock (_DelegateTypes) {
- Type conflict;
- if (_DelegateTypes.TryGetValue(types, out conflict) && conflict != null) {
- type = conflict;
- } else {
- _DelegateTypes[types] = type;
- }
- }
-
- return type;
- }
-
- private static Type MakeNewCustomDelegate(Type[] types) {
- Type returnType = types[types.Length - 1];
- Type[] parameters = types.RemoveLast();
-
- TypeBuilder builder = Snippets.Shared.DefineDelegateType("Delegate" + types.Length);
- builder.DefineConstructor(CtorAttributes, CallingConventions.Standard, _DelegateCtorSignature).SetImplementationFlags(ImplAttributes);
- builder.DefineMethod("Invoke", InvokeAttributes, returnType, parameters).SetImplementationFlags(ImplAttributes);
- return builder.CreateType();
- }
-
- /// <summary>
- /// Returns true if the method should not be displayed in the stack frame.
- /// </summary>
- public static bool IsInvisibleDlrStackFrame(MethodBase mb) {
- //This method name is used for the dynamic method created for a delegate type signature.
- if (mb.Name == "_Scripting_") {
- return true;
- }
-
- //Filters out methods in Microsoft.Scripting namespaces.
- if (mb.DeclaringType != null &&
- mb.DeclaringType.Namespace != null &&
- mb.DeclaringType.Namespace.StartsWith("Microsoft.Scripting", StringComparison.Ordinal)) {
- return true;
- }
-
- //Filters out all the methods generated for DLR rules or used in DLR rules.
- return CallSiteHelpers.IsInternalFrame(mb);
- }
- }
- }