/// <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 static unsafe object GetCastableTargetIfPossible(ICastableObject castableObject, EEType *interfaceType, bool produceException, ref Exception exception) { CastableObjectCacheEntry <object>[] cache = Unsafe.As <CastableObject>(castableObject).Cache; object targetObjectInitial = null; if (cache != null) { targetObjectInitial = CacheLookup(cache, new IntPtr(interfaceType)); if (targetObjectInitial != null) { if (targetObjectInitial != s_castFailCanary) { return(targetObjectInitial); } else if (!produceException) { return(null); } } } // Call into the object to determine if the runtime can perform the cast. This will return null if it fails. object targetObject = castableObject.CastToInterface(new EETypePtr(new IntPtr(interfaceType)), produceException, out exception); // If the target object is null, and that result has already been cached, just return null now. // Otherwise, we need to store the canary in the cache so future failing "is" checks can be fast if (targetObject == null) { if (targetObjectInitial != null) { return(null); } else { targetObject = s_castFailCanary; } } InternalCalls.RhpAcquireCastCacheLock(); // Assuming we reach here, we should attempt to add the newly discovered targetObject to the per-object cache // First, check to see if something is already there // we may have replaced the cache object since the earlier acquisition in this method. Re-acquire the cache object // here. cache = Unsafe.As <CastableObject>(castableObject).Cache; object targetObjectInCache = null; if (cache != null) { targetObjectInCache = CacheLookup(cache, new IntPtr(interfaceType)); } if (targetObjectInCache == null) { // If the target object still isn't in the cache by this point, add it now AddToCastableCache(castableObject, interfaceType, targetObject); targetObjectInCache = targetObject; } InternalCalls.RhpReleaseCastCacheLock(); if (targetObjectInCache != s_castFailCanary) { return(targetObjectInCache); } else { return(null); } }
internal static unsafe object GetCastableTargetIfPossible(ICastableObject castableObject, EEType *interfaceType, bool produceException, ref Exception exception) { CastableObjectCacheEntry[] cache = Unsafe.As<CastableObject>(castableObject).Cache; object targetObjectInitial = null; if (cache != null) { targetObjectInitial = CastableTargetLookup(cache, interfaceType); if (targetObjectInitial != null) { if (targetObjectInitial != s_castFailCanary) return targetObjectInitial; else if (!produceException) return null; } } // Call into the object to determine if the runtime can perform the cast. This will return null if it fails. object targetObject = castableObject.CastToInterface(new EETypePtr(new IntPtr(interfaceType)), produceException, out exception); // If the target object is null, and that result has already been cached, just return null now. // Otherwise, we need to store the canary in the cache so future failing "is" checks can be fast if (targetObject == null) { if (targetObjectInitial != null) return null; else targetObject = s_castFailCanary; } InternalCalls.RhpAcquireCastCacheLock(); // Assuming we reach here, we should attempt to add the newly discovered targetObject to the per-object cache // First, check to see if something is already there // we may have replaced the cache object since the earlier acquisition in this method. Re-acquire the cache object // here. cache = Unsafe.As<CastableObject>(castableObject).Cache; object targetObjectInCache = null; if (cache != null) targetObjectInCache = CastableTargetLookup(cache, interfaceType); if (targetObjectInCache == null) { // If the target object still isn't in the cache by this point, add it now AddToCastableCache(castableObject, interfaceType, targetObject); targetObjectInCache = targetObject; } InternalCalls.RhpReleaseCastCacheLock(); if (targetObjectInCache != s_castFailCanary) return targetObjectInCache; else return null; }
/// <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; }