CallSiteBinder.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / Core / Microsoft / Scripting / Actions / CallSiteBinder.cs / 1305376 / CallSiteBinder.cs

                            /* **************************************************************************** 
 *
 * 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.
 *
 *
 * ***************************************************************************/ 

using System.Collections.Generic; 
using System.Collections.ObjectModel; 
using System.Diagnostics;
using System.Dynamic; 
using System.Dynamic.Utils;
using System.Linq.Expressions;
using System.Threading;
using System.Reflection; 

#if SILVERLIGHT 
using System.Core; 
#endif //SILVERLIGHT
 
namespace System.Runtime.CompilerServices {
    /// 
    /// Class responsible for runtime binding of the dynamic operations on the dynamic call site.
    ///  
    public abstract class CallSiteBinder {
        private static readonly LabelTarget _updateLabel = Expression.Label("CallSiteBinder.UpdateLabel"); 
 
        /// 
        /// The Level 2 cache - all rules produced for the same binder. 
        /// 
        internal Dictionary Cache;

        ///  
        /// Initializes a new instance of the  class.
        ///  
        protected CallSiteBinder() { 
        }
 
        /// 
        /// Gets a label that can be used to cause the binding to be updated. It
        /// indicates that the expression's binding is no longer valid.
        /// This is typically used when the "version" of a dynamic object has 
        /// changed.
        ///  
        public static LabelTarget UpdateLabel { 
            get { return _updateLabel; }
        } 

        private sealed class LambdaSignature where T : class {
            internal static readonly LambdaSignature Instance = new LambdaSignature();
 
            internal readonly ReadOnlyCollection Parameters;
            internal readonly LabelTarget ReturnLabel; 
 
            private LambdaSignature() {
                Type target = typeof(T); 
                if (!typeof(Delegate).IsAssignableFrom(target)) {
                    throw Error.TypeParameterIsNotDelegate(target);
                }
 
                MethodInfo invoke = target.GetMethod("Invoke");
                ParameterInfo[] pis = invoke.GetParametersCached(); 
                if (pis[0].ParameterType != typeof(CallSite)) { 
                    throw Error.FirstArgumentMustBeCallSite();
                } 

                var @params = new ParameterExpression[pis.Length - 1];
                for (int i = 0; i < @params.Length; i++) {
                    @params[i] = Expression.Parameter(pis[i + 1].ParameterType, "$arg" + i); 
                }
 
                Parameters = new TrueReadOnlyCollection(@params); 
                ReturnLabel = Expression.Label(invoke.GetReturnType());
            } 
        }

        /// 
        /// Performs the runtime binding of the dynamic operation on a set of arguments. 
        /// 
        /// An array of arguments to the dynamic operation. 
        /// The array of  instances that represent the parameters of the call site in the binding process. 
        /// A LabelTarget used to return the result of the dynamic binding.
        ///  
        /// An Expression that performs tests on the dynamic operation arguments, and
        /// performs the dynamic operation if hte tests are valid. If the tests fail on
        /// subsequent occurrences of the dynamic operation, Bind will be called again
        /// to produce a new  for the new argument types. 
        /// 
        public abstract Expression Bind(object[] args, ReadOnlyCollection parameters, LabelTarget returnLabel); 
 
        /// 
        /// Provides low-level runtime binding support.  Classes can override this and provide a direct 
        /// delegate for the implementation of rule.  This can enable saving rules to disk, having
        /// specialized rules available at runtime, or providing a different caching policy.
        /// 
        /// The target type of the CallSite. 
        /// The CallSite the bind is being performed for.
        /// The arguments for the binder. 
        /// A new delegate which replaces the CallSite Target. 
        public virtual T BindDelegate(CallSite site, object[] args) where T : class {
            return null; 
        }


        internal T BindCore(CallSite site, object[] args) where T : class { 
            //
            // Try to find a precompiled delegate, and return it if found. 
            // 
            T result = BindDelegate(site, args);
            if (result != null) { 
                return result;
            }

            // 
            // Get the Expression for the binding
            // 
            var signature = LambdaSignature.Instance; 
            Expression binding = Bind(args, signature.Parameters, signature.ReturnLabel);
 
            //
            // Check the produced rule
            //
            if (binding == null) { 
                throw Error.NoOrInvalidRuleProduced();
            } 
 
            //
            // finally produce the new rule if we need to 
            //
#if !MICROSOFT_SCRIPTING_CORE && !SILVERLIGHT
            // We cannot compile rules in the heterogeneous app domains since they
            // may come from less trusted sources 
            // Silverlight always uses a homogenous appdomain, so we don’t need this check
            if (!AppDomain.CurrentDomain.IsHomogenous) { 
                throw Error.HomogenousAppDomainRequired(); 
            }
#endif 
            Expression e = Stitch(binding, signature);
            T newRule = e.Compile();

            CacheTarget(newRule); 

            return newRule; 
        } 

        ///  
        /// Adds a target to the cache of known targets.  The cached targets will
        /// be scanned before calling BindDelegate to produce the new rule.
        /// 
        /// The type of target being added. 
        /// The target delegate to be added to the cache.
        protected void CacheTarget(T target) where T : class { 
            GetRuleCache().AddRule(target); 
        }
 
        private static Expression Stitch(Expression binding, LambdaSignature signature) where T : class {
            Type targetType = typeof(T);
            Type siteType = typeof(CallSite);
 
            var body = new ReadOnlyCollectionBuilder(3);
            body.Add(binding); 
 
            var site = Expression.Parameter(typeof(CallSite), "$site");
            var @params = signature.Parameters.AddFirst(site); 

            Expression updLabel = Expression.Label(CallSiteBinder.UpdateLabel);

#if DEBUG 
            // put the AST into the constant pool for debugging purposes
            updLabel = Expression.Block( 
                Expression.Constant(binding, typeof(Expression)), 
                updLabel
            ); 
#endif

            body.Add(updLabel);
            body.Add( 
                Expression.Label(
                    signature.ReturnLabel, 
                    Expression.Condition( 
                        Expression.Call(
                            typeof(CallSiteOps).GetMethod("SetNotMatched"), 
                            @params.First()
                        ),
                        Expression.Default(signature.ReturnLabel.Type),
                        Expression.Invoke( 
                            Expression.Property(
                                Expression.Convert(site, siteType), 
                                typeof(CallSite).GetProperty("Update") 
                            ),
                            new TrueReadOnlyCollection(@params) 
                        )
                    )
                )
            ); 

            return new Expression( 
                Expression.Block(body), 
                "CallSite.Target",
                true, // always compile the rules with tail call optimization 
                new TrueReadOnlyCollection(@params)
            );
        }
 
        internal RuleCache GetRuleCache() where T : class {
            // make sure we have cache. 
            if (Cache == null) { 
                Interlocked.CompareExchange(ref Cache, new Dictionary(), null);
            } 

            object ruleCache;
            var cache = Cache;
            lock (cache) { 
                if (!cache.TryGetValue(typeof(T), out ruleCache)) {
                    cache[typeof(T)] = ruleCache = new RuleCache(); 
                } 
            }
 
            RuleCache result = ruleCache as RuleCache;
            Debug.Assert(result != null);
            return result;
        } 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
/* **************************************************************************** 
 *
 * 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.
 *
 *
 * ***************************************************************************/ 

using System.Collections.Generic; 
using System.Collections.ObjectModel; 
using System.Diagnostics;
using System.Dynamic; 
using System.Dynamic.Utils;
using System.Linq.Expressions;
using System.Threading;
using System.Reflection; 

#if SILVERLIGHT 
using System.Core; 
#endif //SILVERLIGHT
 
namespace System.Runtime.CompilerServices {
    /// 
    /// Class responsible for runtime binding of the dynamic operations on the dynamic call site.
    ///  
    public abstract class CallSiteBinder {
        private static readonly LabelTarget _updateLabel = Expression.Label("CallSiteBinder.UpdateLabel"); 
 
        /// 
        /// The Level 2 cache - all rules produced for the same binder. 
        /// 
        internal Dictionary Cache;

        ///  
        /// Initializes a new instance of the  class.
        ///  
        protected CallSiteBinder() { 
        }
 
        /// 
        /// Gets a label that can be used to cause the binding to be updated. It
        /// indicates that the expression's binding is no longer valid.
        /// This is typically used when the "version" of a dynamic object has 
        /// changed.
        ///  
        public static LabelTarget UpdateLabel { 
            get { return _updateLabel; }
        } 

        private sealed class LambdaSignature where T : class {
            internal static readonly LambdaSignature Instance = new LambdaSignature();
 
            internal readonly ReadOnlyCollection Parameters;
            internal readonly LabelTarget ReturnLabel; 
 
            private LambdaSignature() {
                Type target = typeof(T); 
                if (!typeof(Delegate).IsAssignableFrom(target)) {
                    throw Error.TypeParameterIsNotDelegate(target);
                }
 
                MethodInfo invoke = target.GetMethod("Invoke");
                ParameterInfo[] pis = invoke.GetParametersCached(); 
                if (pis[0].ParameterType != typeof(CallSite)) { 
                    throw Error.FirstArgumentMustBeCallSite();
                } 

                var @params = new ParameterExpression[pis.Length - 1];
                for (int i = 0; i < @params.Length; i++) {
                    @params[i] = Expression.Parameter(pis[i + 1].ParameterType, "$arg" + i); 
                }
 
                Parameters = new TrueReadOnlyCollection(@params); 
                ReturnLabel = Expression.Label(invoke.GetReturnType());
            } 
        }

        /// 
        /// Performs the runtime binding of the dynamic operation on a set of arguments. 
        /// 
        /// An array of arguments to the dynamic operation. 
        /// The array of  instances that represent the parameters of the call site in the binding process. 
        /// A LabelTarget used to return the result of the dynamic binding.
        ///  
        /// An Expression that performs tests on the dynamic operation arguments, and
        /// performs the dynamic operation if hte tests are valid. If the tests fail on
        /// subsequent occurrences of the dynamic operation, Bind will be called again
        /// to produce a new  for the new argument types. 
        /// 
        public abstract Expression Bind(object[] args, ReadOnlyCollection parameters, LabelTarget returnLabel); 
 
        /// 
        /// Provides low-level runtime binding support.  Classes can override this and provide a direct 
        /// delegate for the implementation of rule.  This can enable saving rules to disk, having
        /// specialized rules available at runtime, or providing a different caching policy.
        /// 
        /// The target type of the CallSite. 
        /// The CallSite the bind is being performed for.
        /// The arguments for the binder. 
        /// A new delegate which replaces the CallSite Target. 
        public virtual T BindDelegate(CallSite site, object[] args) where T : class {
            return null; 
        }


        internal T BindCore(CallSite site, object[] args) where T : class { 
            //
            // Try to find a precompiled delegate, and return it if found. 
            // 
            T result = BindDelegate(site, args);
            if (result != null) { 
                return result;
            }

            // 
            // Get the Expression for the binding
            // 
            var signature = LambdaSignature.Instance; 
            Expression binding = Bind(args, signature.Parameters, signature.ReturnLabel);
 
            //
            // Check the produced rule
            //
            if (binding == null) { 
                throw Error.NoOrInvalidRuleProduced();
            } 
 
            //
            // finally produce the new rule if we need to 
            //
#if !MICROSOFT_SCRIPTING_CORE && !SILVERLIGHT
            // We cannot compile rules in the heterogeneous app domains since they
            // may come from less trusted sources 
            // Silverlight always uses a homogenous appdomain, so we don’t need this check
            if (!AppDomain.CurrentDomain.IsHomogenous) { 
                throw Error.HomogenousAppDomainRequired(); 
            }
#endif 
            Expression e = Stitch(binding, signature);
            T newRule = e.Compile();

            CacheTarget(newRule); 

            return newRule; 
        } 

        ///  
        /// Adds a target to the cache of known targets.  The cached targets will
        /// be scanned before calling BindDelegate to produce the new rule.
        /// 
        /// The type of target being added. 
        /// The target delegate to be added to the cache.
        protected void CacheTarget(T target) where T : class { 
            GetRuleCache().AddRule(target); 
        }
 
        private static Expression Stitch(Expression binding, LambdaSignature signature) where T : class {
            Type targetType = typeof(T);
            Type siteType = typeof(CallSite);
 
            var body = new ReadOnlyCollectionBuilder(3);
            body.Add(binding); 
 
            var site = Expression.Parameter(typeof(CallSite), "$site");
            var @params = signature.Parameters.AddFirst(site); 

            Expression updLabel = Expression.Label(CallSiteBinder.UpdateLabel);

#if DEBUG 
            // put the AST into the constant pool for debugging purposes
            updLabel = Expression.Block( 
                Expression.Constant(binding, typeof(Expression)), 
                updLabel
            ); 
#endif

            body.Add(updLabel);
            body.Add( 
                Expression.Label(
                    signature.ReturnLabel, 
                    Expression.Condition( 
                        Expression.Call(
                            typeof(CallSiteOps).GetMethod("SetNotMatched"), 
                            @params.First()
                        ),
                        Expression.Default(signature.ReturnLabel.Type),
                        Expression.Invoke( 
                            Expression.Property(
                                Expression.Convert(site, siteType), 
                                typeof(CallSite).GetProperty("Update") 
                            ),
                            new TrueReadOnlyCollection(@params) 
                        )
                    )
                )
            ); 

            return new Expression( 
                Expression.Block(body), 
                "CallSite.Target",
                true, // always compile the rules with tail call optimization 
                new TrueReadOnlyCollection(@params)
            );
        }
 
        internal RuleCache GetRuleCache() where T : class {
            // make sure we have cache. 
            if (Cache == null) { 
                Interlocked.CompareExchange(ref Cache, new Dictionary(), null);
            } 

            object ruleCache;
            var cache = Cache;
            lock (cache) { 
                if (!cache.TryGetValue(typeof(T), out ruleCache)) {
                    cache[typeof(T)] = ruleCache = new RuleCache(); 
                } 
            }
 
            RuleCache result = ruleCache as RuleCache;
            Debug.Assert(result != null);
            return result;
        } 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK