/// <summary> /// Tries to get an analysis result of a particular type. /// </summary> /// <param name="graph"> /// The current flow graph. /// </param> /// <param name="result"> /// The analysis result, if one can be fetched or computed. /// </param> /// <typeparam name="T"> /// The type of analysis result to fetch or compute. /// </typeparam> /// <returns> /// <c>true</c> if there is an analyzer to compute the result; /// otherwise, <c>false</c>. /// </returns> public bool TryGetResultAs <T>(FlowGraph graph, out T result) { var t = typeof(T); FlowGraphAnalysisCache cache = null; updateLock.EnterReadLock(); try { int cacheIndex; if (cacheIndices.TryGetValue(t, out cacheIndex)) { cache = distinctCaches[cacheIndex]; } } finally { updateLock.ExitReadLock(); } if (cache != null || TryRegisterDefaultAnalysis(t, graph, out cache)) { result = cache.GetResultAs <T>(graph); return(true); } else { result = default(T); return(false); } }
/// <summary> /// Creates a new analysis cache that incorporates a particular /// analysis. /// </summary> /// <param name="analysis"> /// The analysis to include in the new analysis cache. /// </param> /// <typeparam name="T"> /// The result type of the analysis. /// </typeparam> /// <returns> /// A new analysis cache. /// </returns> public MacroAnalysisCache WithAnalysis <T>(IFlowGraphAnalysis <T> analysis) { updateLock.EnterReadLock(); try { var cache = new FlowGraphAnalysisCache <T>(analysis); return(WithAnalysis(typeof(T), cache, true)); } finally { updateLock.ExitReadLock(); } }
/// <summary> /// Creates the default flow graph analysis cache for a particular type of analysis, /// given a particular control-flow graph. Returns a Boolean that tells if this /// function was successful. /// </summary> /// <param name="type">The type of analysis to get an analysis cache for.</param> /// <param name="graph">The graph to tailor the analysis to.</param> /// <param name="result">An analysis cache, if one can be created.</param> /// <returns> /// <c>true</c> if a default analysis is registered for <paramref name="type"/>; /// otherwise, <c>false</c>.</returns> internal static bool TryGetDefaultAnalysisCache( Type type, FlowGraph graph, out FlowGraphAnalysisCache result) { Func <FlowGraph, FlowGraphAnalysisCache> create; if (defaults.TryGetValue(type, out create)) { result = create(graph); return(true); } else { result = null; return(false); } }
private bool TryRegisterDefaultAnalysis(Type t, FlowGraph graph, out FlowGraphAnalysisCache cache) { updateLock.EnterWriteLock(); try { if (DefaultAnalyses.TryGetDefaultAnalysisCache(t, graph, out cache)) { var newMacroCache = WithAnalysis(t, cache, false); this.cacheIndices = newMacroCache.cacheIndices; this.cacheRefCounts = newMacroCache.cacheRefCounts; this.distinctCaches = newMacroCache.distinctCaches; return(true); } else { return(false); } } finally { updateLock.ExitWriteLock(); } }
private MacroAnalysisCache WithAnalysis( Type t, FlowGraphAnalysisCache cache, bool overwrite) { // Figure out which types the analysis is assignable to. var resultTypes = GetAssignableTypes(t); // Decrement reference counts for those types and maintain // a list of all cache indices with a reference count of zero. var cacheRefCountsBuilder = cacheRefCounts.ToBuilder(); var danglingCaches = new List <int>(); if (overwrite) { // Decrement analysis cache reference counts. Add unreferenced // analysis caches to a list of dangling caches. foreach (var type in resultTypes) { int cacheIndex; if (cacheIndices.TryGetValue(type, out cacheIndex)) { int refCount = cacheRefCountsBuilder[cacheIndex]; refCount--; cacheRefCountsBuilder[cacheIndex] = refCount; if (refCount == 0) { danglingCaches.Add(cacheIndex); } } } } // The next thing we want to do is insert the new analysis cache // and maybe do some cleanup if we really have to. int newCacheIndex; var newCaches = new List <FlowGraphAnalysisCache>(distinctCaches); var cacheIndicesBuilder = cacheIndices.ToBuilder(); int danglingCacheCount = danglingCaches.Count; if (danglingCacheCount > 0) { // If at least one cache has become a dangling cache, then // we can replace it with the new analysis' cache. newCacheIndex = danglingCaches[danglingCacheCount - 1]; newCaches[newCacheIndex] = cache; danglingCaches.RemoveAt(danglingCacheCount - 1); danglingCacheCount--; // If we have more than one dangling cache, then we'll have to // delete all but one of them (one gets overwritten) and rewrite // all indices into the cache list. // // That's pretty expensive, but it should also be very rare. if (danglingCacheCount > 0) { // Efficiently delete all dangling caches from the list // of caches and also construct a mapping of old indices // to new indices. var indexRemapping = new int[newCaches.Count]; var newCacheList = new List <FlowGraphAnalysisCache>(); var danglingCacheSet = new HashSet <int>(danglingCaches); int newIndex = 0; for (int i = 0; i < newCaches.Count; i++) { indexRemapping[i] = newIndex; if (!danglingCacheSet.Contains(i)) { newIndex++; newCacheList.Add(newCaches[i]); } } newCaches = newCacheList; newCacheIndex = indexRemapping [newCacheIndex]; // Rewrite indices into the cache list. foreach (var pair in cacheIndices) { cacheIndicesBuilder[pair.Key] = indexRemapping[pair.Value]; } // Rewrite reference counts. var newRefCountsBuilder = ImmutableDictionary.CreateBuilder <int, int>(); foreach (var pair in cacheRefCountsBuilder) { if (!danglingCacheSet.Contains(pair.Key)) { newRefCountsBuilder[indexRemapping[pair.Key]] = pair.Value; } } cacheRefCountsBuilder = newRefCountsBuilder; } } else { // Otherwise, just add the new cache to the list. newCacheIndex = newCaches.Count; newCaches.Add(cache); } // Update the type-to-cache-index dictionary and increment // the new cache's reference count. int newRefCount = 0; foreach (var type in resultTypes) { if (overwrite || !cacheIndicesBuilder.ContainsKey(type)) { cacheIndicesBuilder[type] = newCacheIndex; newRefCount++; } } cacheRefCountsBuilder[newCacheIndex] = newRefCount; return(new MacroAnalysisCache( newCaches, cacheIndicesBuilder.ToImmutable(), cacheRefCountsBuilder.ToImmutable())); }