llvm::Value *LocalTypeDataCache::tryGet(IRGenFunction &IGF, Key key, bool allowAbstract) { auto it = Map.find(key); if (it == Map.end()) return nullptr; auto &chain = it->second; CacheEntry *best = nullptr; Optional<unsigned> bestCost; CacheEntry *next = chain.Root; while (next) { CacheEntry *cur = next; next = cur->getNext(); // Ignore abstract entries if so requested. if (!allowAbstract && cur->getKind() != CacheEntry::Kind::Concrete) continue; // Ignore unacceptable entries. if (!IGF.isActiveDominancePointDominatedBy(cur->DefinitionPoint)) continue; // If there's a collision, compare by cost, ignoring higher-cost entries. if (best) { // Compute the cost of the best entry if we haven't done so already. // If that's zero, go ahead and short-circuit out. if (!bestCost) { bestCost = best->cost(); if (*bestCost == 0) break; } auto curCost = cur->cost(); if (curCost >= *bestCost) continue; // Replace the best cost and fall through. bestCost = curCost; } best = cur; } // If we didn't find anything, we're done. if (!best) return nullptr; // Okay, we've found the best entry available. switch (best->getKind()) { // For concrete caches, this is easy. case CacheEntry::Kind::Concrete: return static_cast<ConcreteCacheEntry*>(best)->Value; // For abstract caches, we need to follow a path. case CacheEntry::Kind::Abstract: { auto entry = static_cast<AbstractCacheEntry*>(best); // Follow the path. auto &source = AbstractSources[entry->SourceIndex]; auto result = entry->follow(IGF, source); // Following the path automatically caches at every point along it, // including the end. assert(chain.Root->DefinitionPoint == IGF.getActiveDominancePoint()); assert(chain.Root->getKind() == CacheEntry::Kind::Concrete); return result; } } llvm_unreachable("bad cache entry kind"); }
MetadataResponse LocalTypeDataCache::tryGet(IRGenFunction &IGF, LocalTypeDataKey key, bool allowAbstract, DynamicMetadataRequest request) { // Use the caching key. key = key.getCachingKey(); auto it = Map.find(key); if (it == Map.end()) return MetadataResponse(); auto &chain = it->second; CacheEntry *best = nullptr; Optional<OperationCost> bestCost; CacheEntry *next = chain.Root; while (next) { CacheEntry *cur = next; next = cur->getNext(); // Ignore abstract entries if so requested. if (!allowAbstract && !isa<ConcreteCacheEntry>(cur)) continue; // Ignore unacceptable entries. if (!IGF.isActiveDominancePointDominatedBy(cur->DefinitionPoint)) continue; // If there's a collision, compare by cost, ignoring higher-cost entries. if (best) { // Compute the cost of the best entry if we haven't done so already. // If that's zero, go ahead and short-circuit out. if (!bestCost) { bestCost = best->costForRequest(key, request); if (*bestCost == OperationCost::Free) break; } auto curCost = cur->costForRequest(key, request); if (curCost >= *bestCost) continue; // Replace the best cost and fall through. bestCost = curCost; } best = cur; } // If we didn't find anything, we're done. if (!best) return MetadataResponse(); // Okay, we've found the best entry available. switch (best->getKind()) { // For concrete caches, this is easy. case CacheEntry::Kind::Concrete: { auto entry = cast<ConcreteCacheEntry>(best); if (entry->immediatelySatisfies(key, request)) return entry->Value; assert(key.Kind.isAnyTypeMetadata()); // Emit a dynamic check that the type metadata matches the request. // TODO: we could potentially end up calling this redundantly with a // dynamic request. Fortunately, those are used only in very narrow // circumstances. auto response = emitCheckTypeMetadataState(IGF, request, entry->Value); // Add a concrete entry for the checked result. IGF.setScopedLocalTypeData(key, response); return response; } // For abstract caches, we need to follow a path. case CacheEntry::Kind::Abstract: { auto entry = cast<AbstractCacheEntry>(best); // Follow the path. auto &source = AbstractSources[entry->SourceIndex]; auto response = entry->follow(IGF, source, request); // Following the path automatically caches at every point along it, // including the end. assert(chain.Root->DefinitionPoint == IGF.getActiveDominancePoint()); assert(isa<ConcreteCacheEntry>(chain.Root)); return response; } } llvm_unreachable("bad cache entry kind"); }