//===--- 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/Serialization/SerializedSILLoader.h" #include "swift/SIL/SILDebugScope.h" #include "swift/SIL/SILModule.h" #include "Linker.h" #include "swift/SIL/SILVisitor.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 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 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(); return SILWitnessTable::create(*this, linkage, NormalC); } SILWitnessTable * 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()); } SILWitnessTable * SILModule::lookUpWitnessTable(const ProtocolConformance *C, bool deserializeLazily) { assert(C && "null conformance passed to lookUpWitnessTable"); const NormalProtocolConformance *NormalC = C->getRootNormalConformance(); // Attempt to lookup the witness table from the table. auto found = WitnessTableMap.find(NormalC); if (found == WitnessTableMap.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; } 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; // 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; // If we fail, just return the declaration. return wT; } SILDefaultWitnessTable * SILModule::lookUpDefaultWitnessTable(const ProtocolDecl *Protocol) { // Note: we only ever look up default witness tables in the translation unit // that is currently being compiled, since they SILGen generates them when it // visits the protocol declaration, and IRGen emits them when emitting the // protocol descriptor metadata for the protocol. auto found = DefaultWitnessTableMap.find(Protocol); if (found == DefaultWitnessTableMap.end()) { assert(Protocol->hasFixedLayout() && "Resilient protocol must have a default witness table"); return nullptr; } assert(!Protocol->hasFixedLayout() && "Fixed-layout protocol cannot have a default witness table"); return found->second; } SILDefaultWitnessTable * SILModule::createDefaultWitnessTableDeclaration(const ProtocolDecl *Protocol) { assert(!Protocol->hasFixedLayout() && "Fixed-layout protocol cannot have a default witness table"); return SILDefaultWitnessTable::create(*this, Protocol); } 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 || stripExternalFromLinkage(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(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->getAsClassOrClassExtensionContext(); 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(); 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()) F->addSemanticsAttr(cast(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 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(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); } SILFunction *SILModule::hasFunction(StringRef Name, SILLinkage Linkage) { assert(!lookUpFunction(Name) && "hasFunction should be only called for " "functions that are not contained in the " "SILModule yet"); return SILLinkerVisitor(*this, getSILLoader(), SILModule::LinkingMode::LinkNormal) .lookupFunction(Name, Linkage); } void SILModule::linkAllWitnessTables() { getSILLoader()->getAllWitnessTables(); } void SILModule::linkAllVTables() { getSILLoader()->getAllVTables(); } void SILModule::invalidateSILLoaderCaches() { getSILLoader()->invalidateCaches(); } void SILModule::removeFromZombieList(StringRef Name) { if (auto *Zombie = ZombieFunctionTable.lookup(Name)) { ZombieFunctionTable.erase(Name); zombieFunctions.remove(Zombie); } } /// 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); ZombieFunctionTable[copiedName] = 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); } } void SILModule::invalidateFunctionInSILCache(SILFunction *F) { getSILLoader()->invalidateFunction(F); } /// Erase a global SIL variable from the module. void SILModule::eraseGlobalVariable(SILGlobalVariable *G) { GlobalVariableMap.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 = VTableMap.find(C); if (R != VTableMap.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. VTableMap[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(); } static ArrayRef getSubstitutionsForProtocolConformance(ProtocolConformanceRef CRef) { if (CRef.isAbstract()) return {}; auto C = CRef.getConcrete(); // Walk down to the base NormalProtocolConformance. ArrayRef Subs; const ProtocolConformance *ParentC = C; while (!isa(ParentC)) { switch (ParentC->getKind()) { case ProtocolConformanceKind::Normal: llvm_unreachable("should have exited the loop?!"); case ProtocolConformanceKind::Inherited: ParentC = cast(ParentC) ->getInheritedConformance(); break; case ProtocolConformanceKind::Specialized: { auto SC = cast(ParentC); ParentC = SC->getGenericConformance(); assert(Subs.empty() && "multiple conformance specializations?!"); Subs = SC->getGenericSubstitutions(); break; } } } const NormalProtocolConformance *NormalC = cast(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); } return Subs; } /// \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> 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) { DEBUG(llvm::dbgs() << " Failed speculative lookup of witness for: "; C.dump(); Member.dump()); return std::make_tuple(nullptr, nullptr, ArrayRef()); } // Okay, we found the correct witness table. Now look for the method. for (auto &Entry : Ret->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, getSubstitutionsForProtocolConformance(C)); } return std::make_tuple(nullptr, nullptr, ArrayRef()); } 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); } }