BoundConstants.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 / Compiler / BoundConstants.cs / 1305376 / BoundConstants.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.Diagnostics; 
using System.Reflection.Emit;
using System.Runtime.CompilerServices; 
using System.Dynamic.Utils;

#if SILVERLIGHT
using System.Core; 
#endif
 
namespace System.Linq.Expressions.Compiler { 
    /// 
    /// This type tracks "runtime" constants--live objects that appear in 
    /// ConstantExpression nodes and must be bound to the delegate.
    /// 
    internal sealed class BoundConstants {
 
        /// 
        /// Constants can emit themselves as different types 
        /// For caching purposes, we need to treat each distinct Type as a 
        /// seperate thing to cache. (If we have to cast it on the way out, it
        /// ends up using a JIT temp and defeats the purpose of caching the 
        /// value in a local)
        /// 
        private struct TypedConstant : IEquatable {
            internal readonly object Value; 
            internal readonly Type Type;
 
            internal TypedConstant(object value, Type type) { 
                Value = value;
                Type = type; 
            }

            public override int GetHashCode() {
                return RuntimeHelpers.GetHashCode(Value) ^ Type.GetHashCode(); 
            }
            public bool Equals(TypedConstant other) { 
                return object.ReferenceEquals(Value, other.Value) && Type.Equals(other.Type); 
            }
            [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2231:OverloadOperatorEqualsOnOverridingValueTypeEquals")] 
            public override bool Equals(object obj) {
                return (obj is TypedConstant) && Equals((TypedConstant)obj);
            }
        } 

        ///  
        /// The list of constants in the order they appear in the constant array 
        /// 
        private readonly List _values = new List(); 

        /// 
        /// The index of each constant in the constant array
        ///  
        private readonly Dictionary _indexes = new Dictionary(ReferenceEqualityComparer.Instance);
 
        ///  
        /// Each constant referenced within this lambda, and how often it was referenced
        ///  
        private readonly Dictionary _references = new Dictionary();

        /// 
        /// IL locals for storing frequently used constants 
        /// 
        private readonly Dictionary _cache = new Dictionary(); 
 
        internal int Count {
            get { return _values.Count; } 
        }

        internal object[] ToArray() {
            return _values.ToArray(); 
        }
 
        ///  
        /// Called by VariableBinder. Adds the constant to the list (if needed)
        /// and increases the reference count by one 
        /// 
        internal void AddReference(object value, Type type) {
            if (!_indexes.ContainsKey(value)) {
                _indexes.Add(value, _values.Count); 
                _values.Add(value);
            } 
            Helpers.IncrementCount(new TypedConstant(value, type), _references); 
        }
 
        /// 
        /// Emits a live object as a constant
        /// 
        internal void EmitConstant(LambdaCompiler lc, object value, Type type) { 
            Debug.Assert(!ILGen.CanEmitConstant(value, type));
 
            if (!lc.CanEmitBoundConstants) { 
                throw Error.CannotCompileConstant(value);
            } 

            LocalBuilder local;
            if (_cache.TryGetValue(new TypedConstant(value, type), out local)) {
                lc.IL.Emit(OpCodes.Ldloc, local); 
                return;
            } 
            EmitConstantsArray(lc); 
            EmitConstantFromArray(lc, value, type);
        } 

        /// 
        /// Emit code to cache frequently used constants into IL locals,
        /// instead of pulling them out of the array each time 
        /// 
        internal void EmitCacheConstants(LambdaCompiler lc) { 
            int count = 0; 
            foreach (var reference in _references) {
                if (!lc.CanEmitBoundConstants) { 
                    throw Error.CannotCompileConstant(reference.Key.Value);
                }

                if (ShouldCache(reference.Value)) { 
                    count++;
                } 
            } 
            if (count == 0) {
                return; 
            }
            EmitConstantsArray(lc);

            // The same lambda can be in multiple places in the tree, so we 
            // need to clear any locals from last time.
            _cache.Clear(); 
 
            foreach (var reference in _references) {
                if (ShouldCache(reference.Value)) { 
                    if (--count > 0) {
                        // Dup array to keep it on the stack
                        lc.IL.Emit(OpCodes.Dup);
                    } 
                    LocalBuilder local = lc.IL.DeclareLocal(reference.Key.Type);
                    EmitConstantFromArray(lc, reference.Key.Value, local.LocalType); 
                    lc.IL.Emit(OpCodes.Stloc, local); 
                    _cache.Add(reference.Key, local);
                } 
            }
        }

        private static bool ShouldCache(int refCount) { 
            // This caching is too aggressive in the face of conditionals and
            // switch. Also, it is too conservative for variables used inside 
            // of loops. 
            return refCount > 2;
        } 

        private static void EmitConstantsArray(LambdaCompiler lc) {
            Debug.Assert(lc.CanEmitBoundConstants); // this should've been checked already
 
            lc.EmitClosureArgument();
            lc.IL.Emit(OpCodes.Ldfld, typeof(Closure).GetField("Constants")); 
        } 

        private void EmitConstantFromArray(LambdaCompiler lc, object value, Type type) { 
            int index;
            if (!_indexes.TryGetValue(value, out index)) {
                _indexes.Add(value, index = _values.Count);
                _values.Add(value); 
            }
 
            lc.IL.EmitInt(index); 
            lc.IL.Emit(OpCodes.Ldelem_Ref);
            if (type.IsValueType) { 
                lc.IL.Emit(OpCodes.Unbox_Any, type);
            } else if (type != typeof(object)) {
                lc.IL.Emit(OpCodes.Castclass, type);
            } 
        }
    } 
} 

// 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.Diagnostics; 
using System.Reflection.Emit;
using System.Runtime.CompilerServices; 
using System.Dynamic.Utils;

#if SILVERLIGHT
using System.Core; 
#endif
 
namespace System.Linq.Expressions.Compiler { 
    /// 
    /// This type tracks "runtime" constants--live objects that appear in 
    /// ConstantExpression nodes and must be bound to the delegate.
    /// 
    internal sealed class BoundConstants {
 
        /// 
        /// Constants can emit themselves as different types 
        /// For caching purposes, we need to treat each distinct Type as a 
        /// seperate thing to cache. (If we have to cast it on the way out, it
        /// ends up using a JIT temp and defeats the purpose of caching the 
        /// value in a local)
        /// 
        private struct TypedConstant : IEquatable {
            internal readonly object Value; 
            internal readonly Type Type;
 
            internal TypedConstant(object value, Type type) { 
                Value = value;
                Type = type; 
            }

            public override int GetHashCode() {
                return RuntimeHelpers.GetHashCode(Value) ^ Type.GetHashCode(); 
            }
            public bool Equals(TypedConstant other) { 
                return object.ReferenceEquals(Value, other.Value) && Type.Equals(other.Type); 
            }
            [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2231:OverloadOperatorEqualsOnOverridingValueTypeEquals")] 
            public override bool Equals(object obj) {
                return (obj is TypedConstant) && Equals((TypedConstant)obj);
            }
        } 

        ///  
        /// The list of constants in the order they appear in the constant array 
        /// 
        private readonly List _values = new List(); 

        /// 
        /// The index of each constant in the constant array
        ///  
        private readonly Dictionary _indexes = new Dictionary(ReferenceEqualityComparer.Instance);
 
        ///  
        /// Each constant referenced within this lambda, and how often it was referenced
        ///  
        private readonly Dictionary _references = new Dictionary();

        /// 
        /// IL locals for storing frequently used constants 
        /// 
        private readonly Dictionary _cache = new Dictionary(); 
 
        internal int Count {
            get { return _values.Count; } 
        }

        internal object[] ToArray() {
            return _values.ToArray(); 
        }
 
        ///  
        /// Called by VariableBinder. Adds the constant to the list (if needed)
        /// and increases the reference count by one 
        /// 
        internal void AddReference(object value, Type type) {
            if (!_indexes.ContainsKey(value)) {
                _indexes.Add(value, _values.Count); 
                _values.Add(value);
            } 
            Helpers.IncrementCount(new TypedConstant(value, type), _references); 
        }
 
        /// 
        /// Emits a live object as a constant
        /// 
        internal void EmitConstant(LambdaCompiler lc, object value, Type type) { 
            Debug.Assert(!ILGen.CanEmitConstant(value, type));
 
            if (!lc.CanEmitBoundConstants) { 
                throw Error.CannotCompileConstant(value);
            } 

            LocalBuilder local;
            if (_cache.TryGetValue(new TypedConstant(value, type), out local)) {
                lc.IL.Emit(OpCodes.Ldloc, local); 
                return;
            } 
            EmitConstantsArray(lc); 
            EmitConstantFromArray(lc, value, type);
        } 

        /// 
        /// Emit code to cache frequently used constants into IL locals,
        /// instead of pulling them out of the array each time 
        /// 
        internal void EmitCacheConstants(LambdaCompiler lc) { 
            int count = 0; 
            foreach (var reference in _references) {
                if (!lc.CanEmitBoundConstants) { 
                    throw Error.CannotCompileConstant(reference.Key.Value);
                }

                if (ShouldCache(reference.Value)) { 
                    count++;
                } 
            } 
            if (count == 0) {
                return; 
            }
            EmitConstantsArray(lc);

            // The same lambda can be in multiple places in the tree, so we 
            // need to clear any locals from last time.
            _cache.Clear(); 
 
            foreach (var reference in _references) {
                if (ShouldCache(reference.Value)) { 
                    if (--count > 0) {
                        // Dup array to keep it on the stack
                        lc.IL.Emit(OpCodes.Dup);
                    } 
                    LocalBuilder local = lc.IL.DeclareLocal(reference.Key.Type);
                    EmitConstantFromArray(lc, reference.Key.Value, local.LocalType); 
                    lc.IL.Emit(OpCodes.Stloc, local); 
                    _cache.Add(reference.Key, local);
                } 
            }
        }

        private static bool ShouldCache(int refCount) { 
            // This caching is too aggressive in the face of conditionals and
            // switch. Also, it is too conservative for variables used inside 
            // of loops. 
            return refCount > 2;
        } 

        private static void EmitConstantsArray(LambdaCompiler lc) {
            Debug.Assert(lc.CanEmitBoundConstants); // this should've been checked already
 
            lc.EmitClosureArgument();
            lc.IL.Emit(OpCodes.Ldfld, typeof(Closure).GetField("Constants")); 
        } 

        private void EmitConstantFromArray(LambdaCompiler lc, object value, Type type) { 
            int index;
            if (!_indexes.TryGetValue(value, out index)) {
                _indexes.Add(value, index = _values.Count);
                _values.Add(value); 
            }
 
            lc.IL.EmitInt(index); 
            lc.IL.Emit(OpCodes.Ldelem_Ref);
            if (type.IsValueType) { 
                lc.IL.Emit(OpCodes.Unbox_Any, type);
            } else if (type != typeof(object)) {
                lc.IL.Emit(OpCodes.Castclass, type);
            } 
        }
    } 
} 

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