// cache must be a size which is a power of two. internal static unsafe object CastableTargetLookup(CastableObjectCacheEntry[] cache, EEType* interfaceType) { uint cacheMask = (uint)cache.Length - 1; uint bucket = interfaceType->HashCode & cacheMask; uint curbucket = bucket; // hash algorithm is open addressing with linear probing while (curbucket < cache.Length) { if (cache[curbucket].Type == interfaceType) return cache[curbucket].InstanceObjectForType; if (cache[curbucket].Type == null) return null; curbucket++; } // Handle wrap-around case curbucket = 0; while (curbucket < bucket) { if (cache[curbucket].Type == interfaceType) return cache[curbucket].InstanceObjectForType; if (cache[curbucket].Type == null) return null; curbucket++; } return null; }
internal unsafe static int GetCachePopulation(CastableObjectCacheEntry[] cache) { int population = 0; for (int i = 0; i < cache.Length; i++) { if (cache[i].Type != null) population++; } return population; }
/// <summary> /// Add the results of a CastableObject call to the cache if possible. (OOM errors may cause caching failure. An OOM is specified not /// to introduce new failure points though.) /// </summary> internal static unsafe void AddToCastableCache(ICastableObject castableObject, EEType *interfaceType, object objectForType) { CastableObjectCacheEntry <object>[] cache = Unsafe.As <CastableObject>(castableObject).Cache; bool setNewCache = false; // If there is no cache, allocate one if (cache == null) { try { cache = new CastableObjectCacheEntry <object> [8]; } catch (OutOfMemoryException) { // Failed to allocate a cache. That is fine, simply return. return; } setNewCache = true; } // Expand old cache if it isn't big enough. if (GetCachePopulation(cache) > (cache.Length / 2)) { setNewCache = true; CastableObjectCacheEntry <object>[] oldCache = cache; try { cache = new CastableObjectCacheEntry <object> [oldCache.Length * 2]; } catch (OutOfMemoryException) { // Failed to allocate a bigger cache. That is fine, keep the old one. } for (int i = 0; i < oldCache.Length; i++) { if (oldCache[i].Key != default(IntPtr)) { AddToExistingCache(cache, oldCache[i].Key, oldCache[i].Value); } } } AddToExistingCache(cache, new IntPtr(interfaceType), objectForType); if (setNewCache) { Unsafe.As <CastableObject>(castableObject).Cache = cache; } return; }
internal unsafe static void AddToExistingCache(CastableObjectCacheEntry[] cache, EEType* interfaceType, object objectForType) { uint cacheMask = (uint)cache.Length - 1; uint bucket = interfaceType->HashCode & cacheMask; uint curbucket = bucket; // hash algorithm is open addressing with linear probing while (curbucket < cache.Length) { if (cache[curbucket].Type == null) { cache[curbucket].Type = interfaceType; cache[curbucket].InstanceObjectForType = objectForType; return; } curbucket++; } // Handle wrap-around case curbucket = 0; while (curbucket < bucket) { if (cache[curbucket].Type == null) { cache[curbucket].Type = interfaceType; cache[curbucket].InstanceObjectForType = objectForType; return; } curbucket++; } EH.FallbackFailFast(RhFailFastReason.InternalError, null); return; }
/// <summary> /// Add the results of a CastableObject call to the cache if possible. (OOM errors may cause caching failure. An OOM is specified not /// to introduce new failure points though.) /// </summary> internal unsafe static void AddToCastableCache(ICastableObject castableObject, EEType* interfaceType, object objectForType) { CastableObjectCacheEntry[] cache = Unsafe.As<CastableObject>(castableObject).Cache; bool setNewCache = false; // If there is no cache, allocate one if (cache == null) { try { cache = new CastableObjectCacheEntry[8]; } catch (OutOfMemoryException) { // Failed to allocate a cache. That is fine, simply return. return; } setNewCache = true; } // Expand old cache if it isn't big enough. if (GetCachePopulation(cache) > (cache.Length / 2)) { setNewCache = true; CastableObjectCacheEntry[] oldCache = cache; try { cache = new CastableObjectCacheEntry[oldCache.Length * 2]; } catch (OutOfMemoryException) { // Failed to allocate a bigger cache. That is fine, keep the old one. } for (int i = 0; i < oldCache.Length; i++) { if (oldCache[i].Type != null) { AddToExistingCache(cache, oldCache[i].Type, oldCache[i].InstanceObjectForType); } } } AddToExistingCache(cache, interfaceType, objectForType); if (setNewCache) { Unsafe.As<CastableObject>(castableObject).Cache = cache; } return; }