| //===--- SILModule.cpp - SILModule implementation -------------------------===// |
| // |
| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors |
| // Licensed under Apache License v2.0 with Runtime Library Exception |
| // |
| // See http://swift.org/LICENSE.txt for license information |
| // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #define DEBUG_TYPE "sil-module" |
| #include "swift/SIL/SILModule.h" |
| #include "Linker.h" |
| #include "swift/SIL/SILDebugScope.h" |
| #include "swift/SIL/SILVisitor.h" |
| #include "swift/Serialization/SerializedSILLoader.h" |
| #include "swift/SIL/SILValue.h" |
| #include "llvm/ADT/FoldingSet.h" |
| #include "llvm/ADT/SmallString.h" |
| #include "llvm/ADT/StringSwitch.h" |
| #include "llvm/ADT/Statistic.h" |
| #include "llvm/Support/Debug.h" |
| #include <functional> |
| using namespace swift; |
| using namespace Lowering; |
| |
| class SILModule::SerializationCallback : public SerializedSILLoader::Callback { |
| void didDeserialize(Module *M, SILFunction *fn) override { |
| updateLinkage(fn); |
| } |
| |
| void didDeserialize(Module *M, SILGlobalVariable *var) override { |
| updateLinkage(var); |
| |
| // For globals we currently do not support available_externally. |
| // In the interpreter it would result in two instances for a single global: |
| // one in the imported module and one in the main module. |
| var->setDeclaration(true); |
| } |
| |
| void didDeserialize(Module *M, SILVTable *vtable) override { |
| // TODO: should vtables get linkage? |
| //updateLinkage(vtable); |
| } |
| |
| void didDeserialize(Module *M, SILWitnessTable *wt) override { |
| updateLinkage(wt); |
| } |
| |
| template <class T> void updateLinkage(T *decl) { |
| switch (decl->getLinkage()) { |
| case SILLinkage::Public: |
| decl->setLinkage(SILLinkage::PublicExternal); |
| return; |
| case SILLinkage::Hidden: |
| decl->setLinkage(SILLinkage::HiddenExternal); |
| return; |
| case SILLinkage::Shared: |
| decl->setLinkage(SILLinkage::SharedExternal); |
| return; |
| case SILLinkage::Private: |
| decl->setLinkage(SILLinkage::PrivateExternal); |
| return; |
| case SILLinkage::PublicExternal: |
| case SILLinkage::HiddenExternal: |
| case SILLinkage::SharedExternal: |
| case SILLinkage::PrivateExternal: |
| return; |
| } |
| } |
| }; |
| |
| SILModule::SILModule(Module *SwiftModule, SILOptions &Options, |
| const DeclContext *associatedDC, |
| bool wholeModule) |
| : TheSwiftModule(SwiftModule), AssociatedDeclContext(associatedDC), |
| Stage(SILStage::Raw), Callback(new SILModule::SerializationCallback()), |
| wholeModule(wholeModule), Options(Options), Types(*this) { |
| } |
| |
| SILModule::~SILModule() { |
| // Decrement ref count for each SILGlobalVariable with static initializers. |
| for (SILGlobalVariable &v : silGlobals) |
| if (v.getInitializer()) |
| v.getInitializer()->decrementRefCount(); |
| |
| // Drop everything functions in this module reference. |
| // |
| // This is necessary since the functions may reference each other. We don't |
| // need to worry about sil_witness_tables since witness tables reference each |
| // other via protocol conformances and sil_vtables don't reference each other |
| // at all. |
| for (SILFunction &F : *this) |
| F.dropAllReferences(); |
| } |
| |
| void *SILModule::allocate(unsigned Size, unsigned Align) const { |
| if (getASTContext().LangOpts.UseMalloc) |
| return AlignedAlloc(Size, Align); |
| |
| return BPA.Allocate(Size, Align); |
| } |
| |
| void *SILModule::allocateInst(unsigned Size, unsigned Align) const { |
| return AlignedAlloc(Size, Align); |
| } |
| |
| void SILModule::deallocateInst(SILInstruction *I) { |
| AlignedFree(I); |
| } |
| |
| SILWitnessTable * |
| SILModule::createWitnessTableDeclaration(ProtocolConformance *C, |
| SILLinkage linkage) { |
| // If we are passed in a null conformance (a valid value), just return nullptr |
| // since we cannot map a witness table to it. |
| if (!C) |
| return nullptr; |
| |
| // Extract the base NormalProtocolConformance. |
| NormalProtocolConformance *NormalC = C->getRootNormalConformance(); |
| |
| SILWitnessTable *WT = SILWitnessTable::create(*this, |
| linkage, |
| NormalC); |
| return WT; |
| } |
| |
| std::pair<SILWitnessTable *, ArrayRef<Substitution>> |
| SILModule:: |
| lookUpWitnessTable(ProtocolConformanceRef C, bool deserializeLazily) { |
| // If we have an abstract conformance passed in (a legal value), just return |
| // nullptr. |
| if (!C.isConcrete()) |
| return {nullptr, {}}; |
| |
| return lookUpWitnessTable(C.getConcrete()); |
| } |
| |
| std::pair<SILWitnessTable *, ArrayRef<Substitution>> |
| SILModule:: |
| lookUpWitnessTable(const ProtocolConformance *C, bool deserializeLazily) { |
| assert(C && "null conformance passed to lookUpWitnessTable"); |
| |
| // Walk down to the base NormalProtocolConformance. |
| ArrayRef<Substitution> Subs; |
| const ProtocolConformance *ParentC = C; |
| while (!isa<NormalProtocolConformance>(ParentC)) { |
| switch (ParentC->getKind()) { |
| case ProtocolConformanceKind::Normal: |
| llvm_unreachable("should have exited the loop?!"); |
| case ProtocolConformanceKind::Inherited: |
| ParentC = cast<InheritedProtocolConformance>(ParentC) |
| ->getInheritedConformance(); |
| break; |
| case ProtocolConformanceKind::Specialized: { |
| auto SC = cast<SpecializedProtocolConformance>(ParentC); |
| ParentC = SC->getGenericConformance(); |
| assert(Subs.empty() && "multiple conformance specializations?!"); |
| Subs = SC->getGenericSubstitutions(); |
| break; |
| } |
| } |
| } |
| const NormalProtocolConformance *NormalC |
| = cast<NormalProtocolConformance>(ParentC); |
| |
| // If the normal conformance is for a generic type, and we didn't hit a |
| // specialized conformance, collect the substitutions from the generic type. |
| // FIXME: The AST should do this for us. |
| if (NormalC->getType()->isSpecialized() && Subs.empty()) { |
| Subs = NormalC->getType() |
| ->gatherAllSubstitutions(NormalC->getDeclContext()->getParentModule(), |
| nullptr); |
| } |
| |
| // Attempt to lookup the witness table from the table. |
| auto found = WitnessTableLookupCache.find(NormalC); |
| if (found == WitnessTableLookupCache.end()) { |
| #ifndef NDEBUG |
| // Make sure that all witness tables are in the witness table lookup |
| // cache. |
| // |
| // This code should not be hit normally since we add witness tables to the |
| // lookup cache when we create them. We don't just assert here since there |
| // is the potential for a conformance without a witness table to be passed |
| // to this function. |
| for (SILWitnessTable &WT : witnessTables) |
| assert(WT.getConformance() != NormalC && |
| "Found witness table that is not" |
| " in the witness table lookup cache."); |
| #endif |
| return {nullptr, Subs}; |
| } |
| |
| SILWitnessTable *wT = found->second; |
| assert(wT != nullptr && "Should never map a conformance to a null witness" |
| " table."); |
| |
| // If we have a definition, return it. |
| if (wT->isDefinition()) |
| return {wT, Subs}; |
| |
| // Otherwise try to deserialize it. If we succeed return the deserialized |
| // function. |
| // |
| // *NOTE* In practice, wT will be deserializedTable, but I do not want to rely |
| // on that behavior for now. |
| if (deserializeLazily) |
| if (auto deserializedTable = getSILLoader()->lookupWitnessTable(wT)) |
| return {deserializedTable, Subs}; |
| |
| // If we fail, just return the declaration. |
| return {wT, Subs}; |
| } |
| |
| SILFunction *SILModule::getOrCreateFunction(SILLocation loc, |
| StringRef name, |
| SILLinkage linkage, |
| CanSILFunctionType type, |
| IsBare_t isBareSILFunction, |
| IsTransparent_t isTransparent, |
| IsFragile_t isFragile, |
| IsThunk_t isThunk, |
| SILFunction::ClassVisibility_t CV) { |
| if (auto fn = lookUpFunction(name)) { |
| assert(fn->getLoweredFunctionType() == type); |
| assert(fn->getLinkage() == linkage); |
| return fn; |
| } |
| |
| auto fn = SILFunction::create(*this, linkage, name, type, nullptr, |
| loc, isBareSILFunction, isTransparent, |
| isFragile, isThunk, CV); |
| fn->setDebugScope(new (*this) SILDebugScope(loc, *fn)); |
| return fn; |
| } |
| |
| static SILFunction::ClassVisibility_t getClassVisibility(SILDeclRef constant) { |
| if (!constant.hasDecl()) |
| return SILFunction::NotRelevant; |
| |
| // If this declaration is a function which goes into a vtable, then it's |
| // symbol must be as visible as its class. Derived classes even have to put |
| // all less visible methods of the base class into their vtables. |
| |
| auto *FD = dyn_cast<AbstractFunctionDecl>(constant.getDecl()); |
| if (!FD) |
| return SILFunction::NotRelevant; |
| |
| DeclContext *context = FD->getDeclContext(); |
| |
| // Methods from extensions don't go into vtables (yet). |
| if (context->isExtensionContext()) |
| return SILFunction::NotRelevant; |
| |
| auto *classType = context->isClassOrClassExtensionContext(); |
| if (!classType || classType->isFinal()) |
| return SILFunction::NotRelevant; |
| |
| if (FD->isFinal() && !FD->getOverriddenDecl()) |
| return SILFunction::NotRelevant; |
| |
| assert(FD->getEffectiveAccess() <= classType->getEffectiveAccess() && |
| "class must be as visible as its members"); |
| |
| switch (classType->getEffectiveAccess()) { |
| case Accessibility::Private: |
| return SILFunction::NotRelevant; |
| case Accessibility::Internal: |
| return SILFunction::InternalClass; |
| case Accessibility::Public: |
| return SILFunction::PublicClass; |
| } |
| } |
| |
| static bool verifySILSelfParameterType(SILDeclRef DeclRef, |
| SILFunction *F, CanSILFunctionType FTy) { |
| SILModule &M = F->getModule(); |
| SILParameterInfo PInfo = FTy->getSelfParameter(); |
| CanType CTy = PInfo.getType(); |
| SILType Ty = SILType::getPrimitiveObjectType(CTy); |
| |
| // We do not care about trivial parameters (for now). There seem to be |
| // cases where we lower them as unowned. |
| // |
| // *NOTE* We do not run this check when we have a generic type since |
| // *generic types do not have type lowering and are always treated as |
| // *non-trivial since we do not know the type. |
| if (CTy->hasArchetype() || CTy->hasTypeParameter() || |
| M.getTypeLowering(Ty).isTrivial()) |
| return true; |
| |
| // If this function is a constructor or destructor, bail. These have @owned |
| // parameters. |
| if (DeclRef.isConstructor() || DeclRef.isDestructor()) |
| return true; |
| |
| // Otherwise, if this function type has a guaranteed self parameter type, |
| // make sure that we have a +0 self param. |
| return !FTy->getExtInfo().hasGuaranteedSelfParam() || |
| PInfo.isGuaranteed() || PInfo.isIndirectMutating(); |
| } |
| |
| SILFunction *SILModule::getOrCreateFunction(SILLocation loc, |
| SILDeclRef constant, |
| ForDefinition_t forDefinition) { |
| |
| auto name = constant.mangle(); |
| auto constantType = Types.getConstantType(constant).castTo<SILFunctionType>(); |
| SILLinkage linkage = constant.getLinkage(forDefinition); |
| |
| if (auto fn = lookUpFunction(name)) { |
| assert(fn->getLoweredFunctionType() == constantType); |
| assert(fn->getLinkage() == linkage); |
| if (forDefinition) { |
| // In all the cases where getConstantLinkage returns something |
| // different for ForDefinition, it returns an available-externally |
| // linkage. |
| if (isAvailableExternally(fn->getLinkage())) { |
| fn->setLinkage(constant.getLinkage(ForDefinition)); |
| } |
| } |
| return fn; |
| } |
| |
| IsTransparent_t IsTrans = constant.isTransparent()? |
| IsTransparent : IsNotTransparent; |
| IsFragile_t IsFrag = IsNotFragile; |
| if (IsTrans == IsTransparent && (linkage == SILLinkage::Public |
| || linkage == SILLinkage::PublicExternal)) { |
| IsFrag = IsFragile; |
| } |
| |
| EffectsKind EK = constant.hasEffectsAttribute() ? |
| constant.getEffectsAttribute() : EffectsKind::Unspecified; |
| |
| Inline_t inlineStrategy = InlineDefault; |
| if (constant.isNoinline()) |
| inlineStrategy = NoInline; |
| else if (constant.isAlwaysInline()) |
| inlineStrategy = AlwaysInline; |
| |
| auto *F = SILFunction::create(*this, linkage, name, |
| constantType, nullptr, |
| None, IsNotBare, IsTrans, IsFrag, IsNotThunk, |
| getClassVisibility(constant), |
| inlineStrategy, EK); |
| |
| if (forDefinition == ForDefinition_t::ForDefinition) |
| F->setDebugScope(new (*this) SILDebugScope(loc, *F)); |
| |
| F->setGlobalInit(constant.isGlobal()); |
| if (constant.hasDecl()) { |
| if (constant.isForeign && constant.isClangGenerated()) |
| F->setForeignBody(HasForeignBody); |
| |
| auto Attrs = constant.getDecl()->getAttrs(); |
| for (auto A : Attrs.getAttributes<SemanticsAttr, false /*AllowInvalid*/>()) |
| F->addSemanticsAttr(cast<SemanticsAttr>(A)->Value); |
| } |
| |
| F->setDeclContext(constant.hasDecl() ? constant.getDecl() : nullptr); |
| |
| // If this function has a self parameter, make sure that it has a +0 calling |
| // convention. This cannot be done for general function types, since |
| // function_ref's SILFunctionTypes do not have archetypes associated with |
| // it. |
| CanSILFunctionType FTy = F->getLoweredFunctionType(); |
| if (FTy->hasSelfParam()) { |
| (void)verifySILSelfParameterType; |
| assert(verifySILSelfParameterType(constant, F, FTy) && |
| "Invalid signature for SIL Self parameter type"); |
| } |
| |
| |
| return F; |
| } |
| |
| |
| SILFunction *SILModule::getOrCreateSharedFunction(SILLocation loc, |
| StringRef name, |
| CanSILFunctionType type, |
| IsBare_t isBareSILFunction, |
| IsTransparent_t isTransparent, |
| IsFragile_t isFragile, |
| IsThunk_t isThunk) { |
| return getOrCreateFunction(loc, name, SILLinkage::Shared, |
| type, isBareSILFunction, isTransparent, isFragile, |
| isThunk, SILFunction::NotRelevant); |
| } |
| |
| SILFunction *SILModule::getOrCreateFunction( |
| SILLinkage linkage, StringRef name, CanSILFunctionType loweredType, |
| GenericParamList *contextGenericParams, Optional<SILLocation> loc, |
| IsBare_t isBareSILFunction, IsTransparent_t isTrans, IsFragile_t isFragile, |
| IsThunk_t isThunk, SILFunction::ClassVisibility_t classVisibility, |
| Inline_t inlineStrategy, EffectsKind EK, SILFunction *InsertBefore, |
| const SILDebugScope *DebugScope, DeclContext *DC) { |
| return SILFunction::create(*this, linkage, name, loweredType, |
| contextGenericParams, loc, isBareSILFunction, |
| isTrans, isFragile, isThunk, classVisibility, |
| inlineStrategy, EK, InsertBefore, DebugScope, DC); |
| } |
| |
| const IntrinsicInfo &SILModule::getIntrinsicInfo(Identifier ID) { |
| unsigned OldSize = IntrinsicIDCache.size(); |
| IntrinsicInfo &Info = IntrinsicIDCache[ID]; |
| |
| // If the element was is in the cache, return it. |
| if (OldSize == IntrinsicIDCache.size()) |
| return Info; |
| |
| // Otherwise, lookup the ID and Type and store them in the map. |
| StringRef NameRef = getBuiltinBaseName(getASTContext(), ID.str(), Info.Types); |
| Info.ID = |
| (llvm::Intrinsic::ID)getLLVMIntrinsicID(NameRef, !Info.Types.empty()); |
| |
| return Info; |
| } |
| |
| const BuiltinInfo &SILModule::getBuiltinInfo(Identifier ID) { |
| unsigned OldSize = BuiltinIDCache.size(); |
| BuiltinInfo &Info = BuiltinIDCache[ID]; |
| |
| // If the element was is in the cache, return it. |
| if (OldSize == BuiltinIDCache.size()) |
| return Info; |
| |
| // Otherwise, lookup the ID and Type and store them in the map. |
| // Find the matching ID. |
| StringRef OperationName = |
| getBuiltinBaseName(getASTContext(), ID.str(), Info.Types); |
| |
| // Several operation names have suffixes and don't match the name from |
| // Builtins.def, so handle those first. |
| if (OperationName.startswith("fence_")) |
| Info.ID = BuiltinValueKind::Fence; |
| else if (OperationName.startswith("cmpxchg_")) |
| Info.ID = BuiltinValueKind::CmpXChg; |
| else if (OperationName.startswith("atomicrmw_")) |
| Info.ID = BuiltinValueKind::AtomicRMW; |
| else if (OperationName.startswith("atomicload_")) |
| Info.ID = BuiltinValueKind::AtomicLoad; |
| else if (OperationName.startswith("atomicstore_")) |
| Info.ID = BuiltinValueKind::AtomicStore; |
| else { |
| // Switch through the rest of builtins. |
| Info.ID = llvm::StringSwitch<BuiltinValueKind>(OperationName) |
| #define BUILTIN(ID, Name, Attrs) \ |
| .Case(Name, BuiltinValueKind::ID) |
| #include "swift/AST/Builtins.def" |
| .Default(BuiltinValueKind::None); |
| } |
| |
| return Info; |
| } |
| |
| SILFunction *SILModule::lookUpFunction(SILDeclRef fnRef) { |
| auto name = fnRef.mangle(); |
| return lookUpFunction(name); |
| } |
| |
| bool SILModule::linkFunction(SILFunction *Fun, SILModule::LinkingMode Mode) { |
| return SILLinkerVisitor(*this, getSILLoader(), Mode).processFunction(Fun); |
| } |
| |
| bool SILModule::linkFunction(SILDeclRef Decl, SILModule::LinkingMode Mode) { |
| return SILLinkerVisitor(*this, getSILLoader(), Mode).processDeclRef(Decl); |
| } |
| |
| bool SILModule::linkFunction(StringRef Name, SILModule::LinkingMode Mode) { |
| return SILLinkerVisitor(*this, getSILLoader(), Mode).processFunction(Name); |
| } |
| |
| void SILModule::linkAllWitnessTables() { |
| getSILLoader()->getAllWitnessTables(); |
| } |
| |
| void SILModule::linkAllVTables() { |
| getSILLoader()->getAllVTables(); |
| } |
| |
| void SILModule::invalidateSILLoaderCaches() { |
| getSILLoader()->invalidateCaches(); |
| } |
| |
| /// Erase a function from the module. |
| void SILModule::eraseFunction(SILFunction *F) { |
| |
| assert(! F->isZombie() && "zombie function is in list of alive functions"); |
| if (F->isInlined() || F->isExternallyUsedSymbol()) { |
| |
| // The owner of the function's Name is the FunctionTable key. As we remove |
| // the function from the table we have to store the name string elsewhere: |
| // in zombieFunctionNames. |
| StringRef copiedName = F->getName().copy(zombieFunctionNames); |
| FunctionTable.erase(F->getName()); |
| F->Name = copiedName; |
| |
| // The function is dead, but we need it later (at IRGen) for debug info |
| // or vtable stub generation. So we move it into the zombie list. |
| getFunctionList().remove(F); |
| zombieFunctions.push_back(F); |
| F->setZombie(); |
| |
| // This opens dead-function-removal opportunities for called functions. |
| // (References are not needed anymore.) |
| F->dropAllReferences(); |
| } else { |
| FunctionTable.erase(F->getName()); |
| getFunctionList().erase(F); |
| } |
| } |
| |
| /// Erase a global SIL variable from the module. |
| void SILModule::eraseGlobalVariable(SILGlobalVariable *G) { |
| GlobalVariableTable.erase(G->getName()); |
| getSILGlobalList().erase(G); |
| } |
| |
| SILVTable *SILModule::lookUpVTable(const ClassDecl *C) { |
| if (!C) |
| return nullptr; |
| |
| // First try to look up R from the lookup table. |
| auto R = VTableLookupTable.find(C); |
| if (R != VTableLookupTable.end()) |
| return R->second; |
| |
| // If that fails, try to deserialize it. If that fails, return nullptr. |
| SILVTable *Vtbl = |
| SILLinkerVisitor(*this, getSILLoader(), SILModule::LinkingMode::LinkAll) |
| .processClassDecl(C); |
| if (!Vtbl) |
| return nullptr; |
| |
| // If we succeeded, map C -> VTbl in the table and return VTbl. |
| VTableLookupTable[C] = Vtbl; |
| return Vtbl; |
| } |
| |
| SerializedSILLoader *SILModule::getSILLoader() { |
| // If the SILLoader is null, create it. |
| if (!SILLoader) |
| SILLoader = SerializedSILLoader::create(getASTContext(), this, |
| Callback.get()); |
| // Return the SerializedSILLoader. |
| return SILLoader.get(); |
| } |
| |
| |
| /// \brief Given a protocol \p Proto, a member method \p Member and a concrete |
| /// class type \p ConcreteTy, search the witness tables and return the static |
| /// function that matches the member with any specializations may be |
| /// required. Notice that we do not scan the class hierarchy, just the concrete |
| /// class type. |
| std::tuple<SILFunction *, SILWitnessTable *, ArrayRef<Substitution>> |
| SILModule::lookUpFunctionInWitnessTable(ProtocolConformanceRef C, |
| SILDeclRef Member) { |
| // Look up the witness table associated with our protocol conformance from the |
| // SILModule. |
| auto Ret = lookUpWitnessTable(C); |
| |
| // If no witness table was found, bail. |
| if (!Ret.first) { |
| DEBUG(llvm::dbgs() << " Failed speculative lookup of witness for: "; |
| C.dump(); Member.dump()); |
| return std::make_tuple(nullptr, nullptr, ArrayRef<Substitution>()); |
| } |
| |
| // Okay, we found the correct witness table. Now look for the method. |
| for (auto &Entry : Ret.first->getEntries()) { |
| // Look at method entries only. |
| if (Entry.getKind() != SILWitnessTable::WitnessKind::Method) |
| continue; |
| |
| SILWitnessTable::MethodWitness MethodEntry = Entry.getMethodWitness(); |
| // Check if this is the member we were looking for. |
| if (MethodEntry.Requirement != Member) |
| continue; |
| |
| return std::make_tuple(MethodEntry.Witness, Ret.first, Ret.second); |
| } |
| |
| return std::make_tuple(nullptr, nullptr, ArrayRef<Substitution>()); |
| } |
| |
| static ClassDecl *getClassDeclSuperClass(ClassDecl *Class) { |
| Type T = Class->getSuperclass(); |
| if (!T) |
| return nullptr; |
| return T->getCanonicalType()->getClassOrBoundGenericClass(); |
| } |
| |
| SILFunction * |
| SILModule:: |
| lookUpFunctionInVTable(ClassDecl *Class, SILDeclRef Member) { |
| // Until we reach the top of the class hierarchy... |
| while (Class) { |
| // Try to lookup a VTable for Class from the module... |
| auto *Vtbl = lookUpVTable(Class); |
| |
| // Bail, if the lookup of VTable fails. |
| if (!Vtbl) { |
| return nullptr; |
| } |
| |
| // Ok, we have a VTable. Try to lookup the SILFunction implementation from |
| // the VTable. |
| if (SILFunction *F = Vtbl->getImplementation(*this, Member)) |
| return F; |
| |
| // If we fail to lookup the SILFunction, again skip Class and attempt to |
| // resolve the method in the VTable of the super class of Class if such a |
| // super class exists. |
| Class = getClassDeclSuperClass(Class); |
| } |
| |
| return nullptr; |
| } |
| |
| |
| void SILModule:: |
| registerDeleteNotificationHandler(DeleteNotificationHandler* Handler) { |
| // Ask the handler (that can be an analysis, a pass, or some other data |
| // structure) if it wants to receive delete notifications. |
| if (Handler->needsNotifications()) { |
| NotificationHandlers.insert(Handler); |
| } |
| } |
| |
| void SILModule:: |
| removeDeleteNotificationHandler(DeleteNotificationHandler* Handler) { |
| NotificationHandlers.remove(Handler); |
| } |
| |
| void SILModule::notifyDeleteHandlers(ValueBase *V) { |
| for (auto *Handler : NotificationHandlers) { |
| Handler->handleDeleteNotification(V); |
| } |
| } |