CallSiteBinder.cs source code in C# .NET

Source code for the .NET framework in C#



/ 4.0 / 4.0 / untmp / 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 
 * 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; 

using System.Core; 
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 
            // 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(); 
            Expression e = Stitch(binding, signature);
            T newRule = e.Compile();


            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 { 
        private static Expression Stitch(Expression binding, LambdaSignature signature) where T : class {
            Type targetType = typeof(T);
            Type siteType = typeof(CallSite);
            var body = new ReadOnlyCollectionBuilder(3);
            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)), 

                                Expression.Convert(site, siteType), 
                            new TrueReadOnlyCollection(@params) 

            return new Expression( 
                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