The Labs \ Source Viewer \ SSCLI \ Microsoft.JScript \ TRHashtable

  1. // ==++==
  2. //
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. //
  14. // ==--==
  15. namespace Microsoft.JScript
  16. {
  17.    
  18. /*
  19.     This class provides a fast implementation of GetMember and GetDefaultMembers for use by LateBinding.
  20.     The BCL implementation for System.Type is disasterously slow.
  21.     This implementation trades memory for speed and does things lazily.
  22.    
  23.     It also replaces RuntimeMethodInfo instances with wrappers that cache the results of GetParameters and that provide an
  24.     efficient implementation of Invoke.
  25.     */   
  26.    
  27.     using System;
  28.     using System.Reflection;
  29.     using System.Collections;
  30.    
  31.     public sealed class TypeReflector : ScriptObject
  32.     {
  33.         private MemberInfo[] defaultMembers;
  34.         private SimpleHashtable staticMembers;
  35.         private SimpleHashtable instanceMembers;
  36.         private MemberInfo[][] memberInfos;
  37.         private ArrayList memberLookupTable;
  38.         internal Type type;
  39.         private object implementsIReflect;
  40.        
  41.         internal uint hashCode;
  42.         internal TypeReflector next;
  43.        
  44.         private static MemberInfo[] EmptyMembers = new MemberInfo[0];
  45.         private static TRHashtable Table = new TRHashtable();
  46.        
  47.         internal TypeReflector(Type type) : base(null)
  48.         {
  49.             this.defaultMembers = null;
  50.             ArrayList memberLookupTable = new ArrayList(512);
  51.             int count = 0;
  52.             SimpleHashtable staticMembers = new SimpleHashtable(256);
  53.             foreach (MemberInfo member in type.GetMembers(BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy)) {
  54.                 string name = member.Name;
  55.                 object ob = staticMembers[name];
  56.                 if (ob == null) {
  57.                     staticMembers[name] = count++;
  58.                     //Avoid allocating an array until needed
  59.                     memberLookupTable.Add(member);
  60.                 }
  61.                 else {
  62.                     int index = (int)ob;
  63.                     ob = memberLookupTable[index];
  64.                     MemberInfo firstMember = ob as MemberInfo;
  65.                     if (firstMember != null) {
  66.                         MemberInfoList mems = new MemberInfoList();
  67.                         //Allocate a flexarray of MemberInfo, and turn it into a fixed array when GetMember is called for this name
  68.                         mems.Add(firstMember);
  69.                         mems.Add(member);
  70.                         memberLookupTable[index] = mems;
  71.                     }
  72.                     else
  73.                         ((MemberInfoList)ob).Add(member);
  74.                 }
  75.             }
  76.             this.staticMembers = staticMembers;
  77.             SimpleHashtable instanceMembers = new SimpleHashtable(256);
  78.             foreach (MemberInfo member in type.GetMembers(BindingFlags.Public | BindingFlags.Instance)) {
  79.                 string name = member.Name;
  80.                 object ob = instanceMembers[name];
  81.                 if (ob == null) {
  82.                     instanceMembers[name] = count++;
  83.                     //Avoid allocating an array until needed
  84.                     memberLookupTable.Add(member);
  85.                 }
  86.                 else {
  87.                     int index = (int)ob;
  88.                     ob = memberLookupTable[index];
  89.                     MemberInfo firstMember = ob as MemberInfo;
  90.                     if (firstMember != null) {
  91.                         MemberInfoList mems = new MemberInfoList();
  92.                         mems.Add(firstMember);
  93.                         mems.Add(member);
  94.                         memberLookupTable[index] = mems;
  95.                     }
  96.                     else
  97.                         ((MemberInfoList)ob).Add(member);
  98.                 }
  99.             }
  100.             this.instanceMembers = instanceMembers;
  101.             this.memberLookupTable = memberLookupTable;
  102.             this.memberInfos = new MemberInfo[count][];
  103.             this.type = type;
  104.             this.implementsIReflect = null;
  105.             this.hashCode = (uint)type.GetHashCode();
  106.             this.next = null;
  107.         }
  108.        
  109.         internal MemberInfo[] GetDefaultMembers()
  110.         {
  111.             MemberInfo[] result = this.defaultMembers;
  112.             if (result == null) {
  113.                 result = JSBinder.GetDefaultMembers(this.type);
  114.                 if (result == null)
  115.                     result = new MemberInfo[0];
  116.                 TypeReflector.WrapMembers(this.defaultMembers = result);
  117.             }
  118.             return result;
  119.         }
  120.        
  121.         public override MemberInfo[] GetMember(string name, BindingFlags bindingAttr)
  122.         {
  123.             bool lookForInstanceMembers = (bindingAttr & BindingFlags.Instance) != 0;
  124.             SimpleHashtable lookupTable = lookForInstanceMembers ? this.instanceMembers : this.staticMembers;
  125.             object ob = lookupTable[name];
  126.             if (ob == null) {
  127.                 if ((bindingAttr & BindingFlags.IgnoreCase) != 0)
  128.                     ob = lookupTable.IgnoreCaseGet(name);
  129.                 if (ob == null) {
  130.                     if (lookForInstanceMembers && (bindingAttr & BindingFlags.Static) != 0)
  131.                         return this.GetMember(name, bindingAttr & ~BindingFlags.Instance);
  132.                     else
  133.                         return TypeReflector.EmptyMembers;
  134.                 }
  135.             }
  136.             int index = (int)ob;
  137.             MemberInfo[] members = this.memberInfos[index];
  138.             if (members == null)
  139.                 return this.GetNewMemberArray(name, index);
  140.             return members;
  141.         }
  142.        
  143.         private MemberInfo[] GetNewMemberArray(string name, int index)
  144.         {
  145.             MemberInfo[] result = null;
  146.             object ob = this.memberLookupTable[index];
  147.             // ob could be null if another thread got in here before us
  148.             if (ob == null)
  149.                 return this.memberInfos[index];
  150.             MemberInfo member = ob as MemberInfo;
  151.             if (member != null)
  152.                 result = new MemberInfo[] {member};
  153.             else
  154.                 result = ((MemberInfoList)ob).ToArray();
  155.             this.memberInfos[index] = result;
  156.             this.memberLookupTable[index] = null;
  157.             TypeReflector.WrapMembers(result);
  158.             return result;
  159.         }
  160.        
  161.         public override MemberInfo[] GetMembers(BindingFlags bindingAttr)
  162.         {
  163.             throw new JScriptException(JSError.InternalError);
  164.         }
  165.        
  166.         static internal TypeReflector GetTypeReflectorFor(Type type)
  167.         {
  168.             TypeReflector result = TypeReflector.Table[type];
  169.             if (result != null)
  170.                 return result;
  171.             result = new TypeReflector(type);
  172.             lock (TypeReflector.Table) {
  173.                 TypeReflector r = TypeReflector.Table[type];
  174.                 if (r != null)
  175.                     return r;
  176.                 TypeReflector.Table[type] = result;
  177.             }
  178.             return result;
  179.         }
  180.        
  181.         internal bool ImplementsIReflect()
  182.         {
  183.             object result = this.implementsIReflect;
  184.             if (result != null)
  185.                 return (bool)result;
  186.             bool bresult = typeof(IReflect).IsAssignableFrom(this.type);
  187.             this.implementsIReflect = bresult;
  188.             return bresult;
  189.         }
  190.        
  191.        
  192.         private static void WrapMembers(MemberInfo[] members)
  193.         {
  194.             for (int i = 0int n = members.Length; i < n; i++) {
  195.                 MemberInfo mem = members[i];
  196.                 switch (mem.MemberType) {
  197.                     case MemberTypes.Field:
  198.                         members[i] = new JSFieldInfo((FieldInfo)mem);
  199.                         break;
  200.                     case MemberTypes.Method:
  201.                         members[i] = new JSMethodInfo((MethodInfo)mem);
  202.                         break;
  203.                     case MemberTypes.Property:
  204.                         members[i] = new JSPropertyInfo((PropertyInfo)mem);
  205.                         break;
  206.                 }
  207.             }
  208.         }
  209.     }
  210.    
  211.     internal sealed class TRHashtable
  212.     {
  213.         private TypeReflector[] table;
  214.         private int count;
  215.         private int threshold;
  216.        
  217.         internal TRHashtable()
  218.         {
  219.             table = new TypeReflector[511];
  220.             count = 0;
  221.             threshold = 256;
  222.         }
  223.        
  224.         internal TypeReflector this[Type type]
  225.         {
  226.             get {
  227.                 uint hashCode = (uint)type.GetHashCode();
  228.                 int index = (int)(hashCode % (uint)this.table.Length);
  229.                 TypeReflector tr = this.table[index];
  230.                 while (tr != null) {
  231.                     if (tr.type == type)
  232.                         return tr;
  233.                     tr = tr.next;
  234.                 }
  235.                 return null;
  236.             }
  237.             set {
  238.                 Debug.Assert(this[type] == null);
  239.                 if (++this.count >= this.threshold)
  240.                     this.Rehash();
  241.                 int index = (int)(value.hashCode % (uint)this.table.Length);
  242.                 value.next = this.table[index];
  243.                 this.table[index] = value;
  244.             }
  245.         }
  246.        
  247.         private void Rehash()
  248.         {
  249.             TypeReflector[] oldTable = this.table;
  250.             int threshold = this.threshold = oldTable.Length + 1;
  251.             int newCapacity = threshold * 2 - 1;
  252.             TypeReflector[] newTable = this.table = new TypeReflector[newCapacity];
  253.             for (int i = threshold - 1; i-- > 0;) {
  254.                 for (TypeReflector old = oldTable[i]; old != null;) {
  255.                     TypeReflector tr = old;
  256.                     old = old.next;
  257.                     int index = (int)(tr.hashCode % (uint)newCapacity);
  258.                     tr.next = newTable[index];
  259.                     newTable[index] = tr;
  260.                 }
  261.             }
  262.         }
  263.     }
  264. }

Developer Fusion