Example #1
0
        /// <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;
        }
Example #2
0
        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;
        }