//===--- Serialization.cpp - Read and write Swift modules -----------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// #include "Serialization.h" #include "SILFormat.h" #include "swift/AST/ASTContext.h" #include "swift/AST/ASTMangler.h" #include "swift/AST/ASTVisitor.h" #include "swift/AST/AutoDiff.h" #include "swift/AST/DiagnosticsCommon.h" #include "swift/AST/Expr.h" #include "swift/AST/FileSystem.h" #include "swift/AST/ForeignAsyncConvention.h" #include "swift/AST/ForeignErrorConvention.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/IndexSubset.h" #include "swift/AST/Initializer.h" #include "swift/AST/LazyResolver.h" #include "swift/AST/LinkLibrary.h" #include "swift/AST/ParameterList.h" #include "swift/AST/Pattern.h" #include "swift/AST/PrettyStackTrace.h" #include "swift/AST/PropertyWrappers.h" #include "swift/AST/ProtocolConformance.h" #include "swift/AST/SILLayout.h" #include "swift/AST/SourceFile.h" #include "swift/AST/SynthesizedFileUnit.h" #include "swift/AST/TypeCheckRequests.h" #include "swift/AST/TypeVisitor.h" #include "swift/Basic/Defer.h" #include "swift/Basic/Dwarf.h" #include "swift/Basic/FileSystem.h" #include "swift/Basic/STLExtras.h" #include "swift/Basic/Version.h" #include "swift/ClangImporter/ClangImporter.h" #include "swift/ClangImporter/ClangModule.h" #include "swift/ClangImporter/SwiftAbstractBasicWriter.h" #include "swift/Demangling/ManglingMacros.h" #include "swift/Serialization/SerializationOptions.h" #include "swift/Strings.h" #include "clang/AST/DeclTemplate.h" #include "swift/SymbolGraphGen/SymbolGraphOptions.h" #include "swift/SymbolGraphGen/SymbolGraphGen.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Bitcode/BitcodeConvenience.h" #include "llvm/Bitstream/BitstreamWriter.h" #include "llvm/Config/config.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/Chrono.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/DJB.h" #include "llvm/Support/EndianStream.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/OnDiskHashTable.h" #include "llvm/Support/Path.h" #include "llvm/Support/SmallVectorMemoryBuffer.h" #include "llvm/Support/raw_ostream.h" #include using namespace swift; using namespace swift::serialization; using namespace llvm::support; using swift::version::Version; using llvm::BCBlockRAII; ASTContext &SerializerBase::getASTContext() const { return M->getASTContext(); } /// Used for static_assert. static constexpr bool declIDFitsIn32Bits() { using Int32Info = std::numeric_limits; using PtrIntInfo = std::numeric_limits; using DeclIDTraits = llvm::PointerLikeTypeTraits; return PtrIntInfo::digits - DeclIDTraits::NumLowBitsAvailable <= Int32Info::digits; } /// Used for static_assert. static constexpr bool bitOffsetFitsIn32Bits() { // FIXME: Considering BitOffset is a _bit_ offset, and we're storing it in 31 // bits of a PointerEmbeddedInt, the maximum offset inside a modulefile we can // handle happens at 2**28 _bytes_, which is only 268MB. Considering // Swift.swiftmodule is itself 25MB, it seems entirely possible users will // exceed this limit. using Int32Info = std::numeric_limits; using PtrIntInfo = std::numeric_limits; using BitOffsetTraits = llvm::PointerLikeTypeTraits; return PtrIntInfo::digits - BitOffsetTraits::NumLowBitsAvailable <= Int32Info::digits; } namespace { /// Used to serialize the on-disk decl hash table. class DeclTableInfo { public: using key_type = DeclBaseName; using key_type_ref = key_type; using data_type = Serializer::DeclTableData; using data_type_ref = const data_type &; using hash_value_type = uint32_t; using offset_type = unsigned; hash_value_type ComputeHash(key_type_ref key) { switch (key.getKind()) { case DeclBaseName::Kind::Normal: assert(!key.empty()); return llvm::djbHash(key.getIdentifier().str(), SWIFTMODULE_HASH_SEED); case DeclBaseName::Kind::Subscript: return static_cast(DeclNameKind::Subscript); case DeclBaseName::Kind::Constructor: return static_cast(DeclNameKind::Constructor); case DeclBaseName::Kind::Destructor: return static_cast(DeclNameKind::Destructor); } llvm_unreachable("unhandled kind"); } std::pair EmitKeyDataLength(raw_ostream &out, key_type_ref key, data_type_ref data) { uint32_t keyLength = sizeof(uint8_t); // For the flag of the name's kind if (key.getKind() == DeclBaseName::Kind::Normal) { keyLength += key.getIdentifier().str().size(); // The name's length } assert(keyLength == static_cast(keyLength)); uint32_t dataLength = (sizeof(uint32_t) + 1) * data.size(); assert(dataLength == static_cast(dataLength)); endian::Writer writer(out, little); writer.write(keyLength); writer.write(dataLength); return { keyLength, dataLength }; } void EmitKey(raw_ostream &out, key_type_ref key, unsigned len) { endian::Writer writer(out, little); switch (key.getKind()) { case DeclBaseName::Kind::Normal: writer.write(static_cast(DeclNameKind::Normal)); writer.OS << key.getIdentifier().str(); break; case DeclBaseName::Kind::Subscript: writer.write(static_cast(DeclNameKind::Subscript)); break; case DeclBaseName::Kind::Constructor: writer.write(static_cast(DeclNameKind::Constructor)); break; case DeclBaseName::Kind::Destructor: writer.write(static_cast(DeclNameKind::Destructor)); break; } } void EmitData(raw_ostream &out, key_type_ref key, data_type_ref data, unsigned len) { static_assert(declIDFitsIn32Bits(), "DeclID too large"); endian::Writer writer(out, little); for (auto entry : data) { writer.write(entry.first); writer.write(entry.second); } } }; class ExtensionTableInfo { serialization::Serializer &Serializer; llvm::SmallDenseMap MangledNameCache; public: explicit ExtensionTableInfo(serialization::Serializer &serializer) : Serializer(serializer) {} using key_type = Identifier; using key_type_ref = key_type; using data_type = Serializer::ExtensionTableData; using data_type_ref = const data_type &; using hash_value_type = uint32_t; using offset_type = unsigned; hash_value_type ComputeHash(key_type_ref key) { assert(!key.empty()); return llvm::djbHash(key.str(), SWIFTMODULE_HASH_SEED); } int32_t getNameDataForBase(const NominalTypeDecl *nominal, StringRef *dataToWrite = nullptr) { if (nominal->getDeclContext()->isModuleScopeContext()) return -Serializer.addContainingModuleRef(nominal->getDeclContext()); auto &mangledName = MangledNameCache[nominal]; if (mangledName.empty()) mangledName = Mangle::ASTMangler().mangleNominalType(nominal); assert(llvm::isUInt<31>(mangledName.size())); if (dataToWrite) *dataToWrite = mangledName; return mangledName.size(); } std::pair EmitKeyDataLength(raw_ostream &out, key_type_ref key, data_type_ref data) { uint32_t keyLength = key.str().size(); assert(keyLength == static_cast(keyLength)); uint32_t dataLength = (sizeof(uint32_t) * 2) * data.size(); for (auto dataPair : data) { int32_t nameData = getNameDataForBase(dataPair.first); if (nameData > 0) dataLength += nameData; } assert(dataLength == static_cast(dataLength)); endian::Writer writer(out, little); writer.write(keyLength); writer.write(dataLength); return { keyLength, dataLength }; } void EmitKey(raw_ostream &out, key_type_ref key, unsigned len) { out << key.str(); } void EmitData(raw_ostream &out, key_type_ref key, data_type_ref data, unsigned len) { static_assert(declIDFitsIn32Bits(), "DeclID too large"); endian::Writer writer(out, little); for (auto entry : data) { StringRef dataToWrite; writer.write(entry.second); writer.write(getNameDataForBase(entry.first, &dataToWrite)); out << dataToWrite; } } }; class LocalDeclTableInfo { public: using key_type = std::string; using key_type_ref = StringRef; using data_type = DeclID; using data_type_ref = const data_type &; using hash_value_type = uint32_t; using offset_type = unsigned; hash_value_type ComputeHash(key_type_ref key) { assert(!key.empty()); return llvm::djbHash(key, SWIFTMODULE_HASH_SEED); } std::pair EmitKeyDataLength(raw_ostream &out, key_type_ref key, data_type_ref data) { uint32_t keyLength = key.size(); assert(keyLength == static_cast(keyLength)); uint32_t dataLength = sizeof(uint32_t); endian::Writer writer(out, little); writer.write(keyLength); // No need to write the data length; it's constant. return { keyLength, dataLength }; } void EmitKey(raw_ostream &out, key_type_ref key, unsigned len) { out << key; } void EmitData(raw_ostream &out, key_type_ref key, data_type_ref data, unsigned len) { static_assert(declIDFitsIn32Bits(), "DeclID too large"); endian::Writer writer(out, little); writer.write(data); } }; using LocalTypeHashTableGenerator = llvm::OnDiskChainedHashTableGenerator; class NestedTypeDeclsTableInfo { public: using key_type = Identifier; using key_type_ref = const key_type &; using data_type = Serializer::NestedTypeDeclsData; // (parent, child) pairs using data_type_ref = const data_type &; using hash_value_type = uint32_t; using offset_type = unsigned; hash_value_type ComputeHash(key_type_ref key) { assert(!key.empty()); return llvm::djbHash(key.str(), SWIFTMODULE_HASH_SEED); } std::pair EmitKeyDataLength(raw_ostream &out, key_type_ref key, data_type_ref data) { uint32_t keyLength = key.str().size(); assert(keyLength == static_cast(keyLength)); uint32_t dataLength = (sizeof(uint32_t) * 2) * data.size(); assert(dataLength == static_cast(dataLength)); endian::Writer writer(out, little); writer.write(keyLength); writer.write(dataLength); return { keyLength, dataLength }; } void EmitKey(raw_ostream &out, key_type_ref key, unsigned len) { // FIXME: Avoid writing string data for identifiers here. out << key.str(); } void EmitData(raw_ostream &out, key_type_ref key, data_type_ref data, unsigned len) { static_assert(declIDFitsIn32Bits(), "DeclID too large"); endian::Writer writer(out, little); for (auto entry : data) { writer.write(entry.first); writer.write(entry.second); } } }; class DeclMemberNamesTableInfo { public: using key_type = DeclBaseName; using key_type_ref = const key_type &; using data_type = BitOffset; // Offsets to sub-tables using data_type_ref = const data_type &; using hash_value_type = uint32_t; using offset_type = unsigned; hash_value_type ComputeHash(key_type_ref key) { switch (key.getKind()) { case DeclBaseName::Kind::Normal: assert(!key.empty()); return llvm::djbHash(key.getIdentifier().str(), SWIFTMODULE_HASH_SEED); case DeclBaseName::Kind::Subscript: return static_cast(DeclNameKind::Subscript); case DeclBaseName::Kind::Constructor: return static_cast(DeclNameKind::Constructor); case DeclBaseName::Kind::Destructor: return static_cast(DeclNameKind::Destructor); } llvm_unreachable("unhandled kind"); } std::pair EmitKeyDataLength(raw_ostream &out, key_type_ref key, data_type_ref data) { uint32_t keyLength = sizeof(uint8_t); // For the flag of the name's kind if (key.getKind() == DeclBaseName::Kind::Normal) { keyLength += key.getIdentifier().str().size(); // The name's length } assert(keyLength == static_cast(keyLength)); uint32_t dataLength = sizeof(uint32_t); endian::Writer writer(out, little); writer.write(keyLength); // No need to write dataLength, it's constant. return { keyLength, dataLength }; } void EmitKey(raw_ostream &out, key_type_ref key, unsigned len) { endian::Writer writer(out, little); switch (key.getKind()) { case DeclBaseName::Kind::Normal: writer.write(static_cast(DeclNameKind::Normal)); writer.OS << key.getIdentifier().str(); break; case DeclBaseName::Kind::Subscript: writer.write(static_cast(DeclNameKind::Subscript)); break; case DeclBaseName::Kind::Constructor: writer.write(static_cast(DeclNameKind::Constructor)); break; case DeclBaseName::Kind::Destructor: writer.write(static_cast(DeclNameKind::Destructor)); break; } } void EmitData(raw_ostream &out, key_type_ref key, data_type_ref data, unsigned len) { static_assert(bitOffsetFitsIn32Bits(), "BitOffset too large"); endian::Writer writer(out, little); writer.write(static_cast(data)); } }; class DeclMembersTableInfo { public: using key_type = DeclID; using key_type_ref = const key_type &; using data_type = Serializer::DeclMembersData; // Vector of DeclIDs using data_type_ref = const data_type &; using hash_value_type = uint32_t; using offset_type = unsigned; hash_value_type ComputeHash(key_type_ref key) { return llvm::hash_value(static_cast(key)); } std::pair EmitKeyDataLength(raw_ostream &out, key_type_ref key, data_type_ref data) { // This will trap if a single ValueDecl has more than 16383 members // with the same DeclBaseName. Seems highly unlikely. assert((data.size() < (1 << 14)) && "Too many members"); uint32_t dataLength = sizeof(uint32_t) * data.size(); // value DeclIDs endian::Writer writer(out, little); // No need to write the key length; it's constant. writer.write(dataLength); return { sizeof(uint32_t), dataLength }; } void EmitKey(raw_ostream &out, key_type_ref key, unsigned len) { static_assert(declIDFitsIn32Bits(), "DeclID too large"); assert(len == sizeof(uint32_t)); endian::Writer writer(out, little); writer.write(key); } void EmitData(raw_ostream &out, key_type_ref key, data_type_ref data, unsigned len) { static_assert(declIDFitsIn32Bits(), "DeclID too large"); endian::Writer writer(out, little); for (auto entry : data) { writer.write(entry); } } }; // Side table information for serializing the table keyed under // \c DeclFingerprintsLayout. class DeclFingerprintsTableInfo { public: using key_type = DeclID; using key_type_ref = const key_type &; using data_type = Fingerprint; using data_type_ref = const data_type &; using hash_value_type = uint32_t; using offset_type = unsigned; hash_value_type ComputeHash(key_type_ref key) { return llvm::hash_value(static_cast(key)); } std::pair EmitKeyDataLength(raw_ostream &out, key_type_ref key, data_type_ref data) { endian::Writer writer(out, little); // No need to write the key or value length; they're both constant. const unsigned valueLen = Fingerprint::DIGEST_LENGTH; return {sizeof(uint32_t), valueLen}; } void EmitKey(raw_ostream &out, key_type_ref key, unsigned len) { static_assert(declIDFitsIn32Bits(), "DeclID too large"); assert(len == sizeof(uint32_t)); endian::Writer writer(out, little); writer.write(key); } void EmitData(raw_ostream &out, key_type_ref key, data_type_ref data, unsigned len) { static_assert(declIDFitsIn32Bits(), "DeclID too large"); assert(len == Fingerprint::DIGEST_LENGTH); endian::Writer writer(out, little); out << data; } }; } // end anonymous namespace static ModuleDecl *getModule(ModuleOrSourceFile DC) { if (auto M = DC.dyn_cast()) return M; return DC.get()->getParentModule(); } static ASTContext &getContext(ModuleOrSourceFile DC) { return getModule(DC)->getASTContext(); } static bool shouldSerializeAsLocalContext(const DeclContext *DC) { return DC->isLocalContext() && !isa(DC) && !isa(DC) && !isa(DC); } namespace { struct Accessors { uint8_t OpaqueReadOwnership; uint8_t ReadImpl, WriteImpl, ReadWriteImpl; SmallVector Decls; }; } // end anonymous namespace static uint8_t getRawOpaqueReadOwnership(swift::OpaqueReadOwnership ownership) { switch (ownership) { #define CASE(KIND) \ case swift::OpaqueReadOwnership::KIND: \ return uint8_t(serialization::OpaqueReadOwnership::KIND); CASE(Owned) CASE(Borrowed) CASE(OwnedOrBorrowed) #undef CASE } llvm_unreachable("bad kind"); } static uint8_t getRawReadImplKind(swift::ReadImplKind kind) { switch (kind) { #define CASE(KIND) \ case swift::ReadImplKind::KIND: \ return uint8_t(serialization::ReadImplKind::KIND); CASE(Stored) CASE(Get) CASE(Inherited) CASE(Address) CASE(Read) #undef CASE } llvm_unreachable("bad kind"); } static unsigned getRawWriteImplKind(swift::WriteImplKind kind) { switch (kind) { #define CASE(KIND) \ case swift::WriteImplKind::KIND: \ return uint8_t(serialization::WriteImplKind::KIND); CASE(Immutable) CASE(Stored) CASE(Set) CASE(StoredWithObservers) CASE(InheritedWithObservers) CASE(MutableAddress) CASE(Modify) #undef CASE } llvm_unreachable("bad kind"); } static unsigned getRawReadWriteImplKind(swift::ReadWriteImplKind kind) { switch (kind) { #define CASE(KIND) \ case swift::ReadWriteImplKind::KIND: \ return uint8_t(serialization::ReadWriteImplKind::KIND); CASE(Immutable) CASE(Stored) CASE(MutableAddress) CASE(MaterializeToTemporary) CASE(Modify) CASE(StoredWithDidSet) CASE(InheritedWithDidSet) #undef CASE } llvm_unreachable("bad kind"); } static Accessors getAccessors(const AbstractStorageDecl *storage) { Accessors accessors; accessors.OpaqueReadOwnership = getRawOpaqueReadOwnership(storage->getOpaqueReadOwnership()); auto impl = storage->getImplInfo(); accessors.ReadImpl = getRawReadImplKind(impl.getReadImpl()); accessors.WriteImpl = getRawWriteImplKind(impl.getWriteImpl()); accessors.ReadWriteImpl = getRawReadWriteImplKind(impl.getReadWriteImpl()); auto decls = storage->getAllAccessors(); accessors.Decls.append(decls.begin(), decls.end()); return accessors; } LocalDeclContextID Serializer::addLocalDeclContextRef(const DeclContext *DC) { assert(DC->isLocalContext() && "Expected a local DeclContext"); return LocalDeclContextsToSerialize.addRef(DC); } GenericSignatureID Serializer::addGenericSignatureRef(GenericSignature sig) { if (!sig) return 0; return GenericSignaturesToSerialize.addRef(sig); } SubstitutionMapID Serializer::addSubstitutionMapRef(SubstitutionMap substitutions) { return SubstitutionMapsToSerialize.addRef(substitutions); } DeclContextID Serializer::addDeclContextRef(const DeclContext *DC) { assert(DC && "cannot reference a null DeclContext"); switch (DC->getContextKind()) { case DeclContextKind::Module: case DeclContextKind::FileUnit: // Skip up to the module return DeclContextID(); default: break; } // If this decl context is a plain old serializable decl, queue it up for // normal serialization. if (shouldSerializeAsLocalContext(DC)) return DeclContextID::forLocalDeclContext(addLocalDeclContextRef(DC)); return DeclContextID::forDecl(addDeclRef(DC->getAsDecl())); } DeclID Serializer::addDeclRef(const Decl *D, bool allowTypeAliasXRef) { assert((!D || !isDeclXRef(D) || isa(D) || isa(D) || isa(D)) && "cannot cross-reference this decl"); assert((!D || !isDeclXRef(D) || !D->getAttrs().hasAttribute()) && "cannot cross-reference this decl"); assert((!D || allowTypeAliasXRef || !isa(D) || D->getModuleContext() == M) && "cannot cross-reference typealiases directly (use the TypeAliasType)"); return DeclsToSerialize.addRef(D); } serialization::TypeID Serializer::addTypeRef(Type ty) { Type typeToSerialize = ty; if (ty) { if (auto nominalDecl = ty->getAnyNominal()) { if (auto structDecl = dyn_cast(nominalDecl)) { if (auto templateInstantiationType = structDecl->getTemplateInstantiationType()) { typeToSerialize = templateInstantiationType; } } } } #ifndef NDEBUG PrettyStackTraceType trace(M->getASTContext(), "serializing", typeToSerialize); assert((allowCompilerErrors() || !typeToSerialize || !typeToSerialize->hasError()) && "serializing type with an error"); #endif return TypesToSerialize.addRef(typeToSerialize); } serialization::ClangTypeID Serializer::addClangTypeRef(const clang::Type *ty) { if (!ty) return 0; // Try to serialize the non-canonical type, but fall back to the // canonical type if necessary. auto loader = getASTContext().getClangModuleLoader(); bool isSerializable; if (loader->isSerializable(ty, false)) { isSerializable = true; } else if (!ty->isCanonicalUnqualified()) { ty = ty->getCanonicalTypeInternal().getTypePtr(); isSerializable = loader->isSerializable(ty, false); } else { isSerializable = false; } if (!isSerializable) { PrettyStackTraceClangType trace(loader->getClangASTContext(), "staging a serialized reference to", ty); llvm::report_fatal_error("Clang function type is not serializable"); } return ClangTypesToSerialize.addRef(ty); } IdentifierID Serializer::addDeclBaseNameRef(DeclBaseName ident) { switch (ident.getKind()) { case DeclBaseName::Kind::Normal: { if (ident.empty()) return 0; IdentifierID &id = IdentifierIDs[ident.getIdentifier()]; if (id != 0) return id; id = ++LastUniquedStringID; StringsToWrite.push_back(ident.getIdentifier().str()); return id; } case DeclBaseName::Kind::Subscript: return SUBSCRIPT_ID; case DeclBaseName::Kind::Constructor: return CONSTRUCTOR_ID; case DeclBaseName::Kind::Destructor: return DESTRUCTOR_ID; } llvm_unreachable("unhandled kind"); } std::pair Serializer::addUniquedString(StringRef str) { if (str.empty()) return {str, 0}; decltype(UniquedStringIDs)::iterator iter; bool isNew; std::tie(iter, isNew) = UniquedStringIDs.insert({str, LastUniquedStringID + 1}); if (!isNew) return {iter->getKey(), iter->getValue()}; ++LastUniquedStringID; // Note that we use the string data stored in the StringMap. StringsToWrite.push_back(iter->getKey()); return {iter->getKey(), LastUniquedStringID}; } IdentifierID Serializer::addFilename(StringRef filename) { assert(!filename.empty() && "Attemping to add an empty filename"); return addUniquedString(filename).second; } IdentifierID Serializer::addContainingModuleRef(const DeclContext *DC) { assert(!isa(DC) && "References should be to things within modules"); const FileUnit *file = cast(DC->getModuleScopeContext()); const ModuleDecl *M = file->getParentModule(); if (M == this->M) return CURRENT_MODULE_ID; if (M == this->M->getASTContext().TheBuiltinModule) return BUILTIN_MODULE_ID; auto clangImporter = static_cast( this->M->getASTContext().getClangModuleLoader()); if (M == clangImporter->getImportedHeaderModule()) return OBJC_HEADER_MODULE_ID; auto exportedModuleName = file->getExportedModuleName(); assert(!exportedModuleName.empty()); auto exportedModuleID = M->getASTContext().getIdentifier(exportedModuleName); return addDeclBaseNameRef(exportedModuleID); } IdentifierID Serializer::addModuleRef(const ModuleDecl *module) { if (module == this->M) return CURRENT_MODULE_ID; if (module == this->M->getASTContext().TheBuiltinModule) return BUILTIN_MODULE_ID; auto moduleName = module->getASTContext().getIdentifier(module->getName().str()); return addDeclBaseNameRef(moduleName); } SILLayoutID Serializer::addSILLayoutRef(const SILLayout *layout) { return SILLayoutsToSerialize.addRef(layout); } NormalConformanceID Serializer::addConformanceRef(const NormalProtocolConformance *conformance) { assert(conformance->getDeclContext()->getParentModule() == M && "cannot reference conformance from another module"); return NormalConformancesToSerialize.addRef(conformance); } /// Record the name of a block. void SerializerBase::emitBlockID(unsigned ID, StringRef name, SmallVectorImpl &nameBuffer) { SmallVector idBuffer; idBuffer.push_back(ID); Out.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID, idBuffer); // Emit the block name if present. if (name.empty()) return; nameBuffer.resize(name.size()); memcpy(nameBuffer.data(), name.data(), name.size()); Out.EmitRecord(llvm::bitc::BLOCKINFO_CODE_BLOCKNAME, nameBuffer); } void SerializerBase::emitRecordID(unsigned ID, StringRef name, SmallVectorImpl &nameBuffer) { assert(ID < 256 && "can't fit record ID in next to name"); nameBuffer.resize(name.size()+1); nameBuffer[0] = ID; memcpy(nameBuffer.data()+1, name.data(), name.size()); Out.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, nameBuffer); } void Serializer::writeBlockInfoBlock() { BCBlockRAII restoreBlock(Out, llvm::bitc::BLOCKINFO_BLOCK_ID, 2); SmallVector nameBuffer; #define BLOCK(X) emitBlockID(X ## _ID, #X, nameBuffer) #define BLOCK_RECORD(K, X) emitRecordID(K::X, #X, nameBuffer) BLOCK(MODULE_BLOCK); BLOCK(CONTROL_BLOCK); BLOCK_RECORD(control_block, METADATA); BLOCK_RECORD(control_block, MODULE_NAME); BLOCK_RECORD(control_block, TARGET); BLOCK(OPTIONS_BLOCK); BLOCK_RECORD(options_block, SDK_PATH); BLOCK_RECORD(options_block, XCC); BLOCK_RECORD(options_block, IS_SIB); BLOCK_RECORD(options_block, IS_TESTABLE); BLOCK_RECORD(options_block, ARE_PRIVATE_IMPORTS_ENABLED); BLOCK_RECORD(options_block, RESILIENCE_STRATEGY); BLOCK_RECORD(options_block, IS_ALLOW_MODULE_WITH_COMPILER_ERRORS_ENABLED); BLOCK_RECORD(options_block, MODULE_ABI_NAME); BLOCK(INPUT_BLOCK); BLOCK_RECORD(input_block, IMPORTED_MODULE); BLOCK_RECORD(input_block, LINK_LIBRARY); BLOCK_RECORD(input_block, IMPORTED_HEADER); BLOCK_RECORD(input_block, IMPORTED_HEADER_CONTENTS); BLOCK_RECORD(input_block, MODULE_FLAGS); BLOCK_RECORD(input_block, SEARCH_PATH); BLOCK_RECORD(input_block, FILE_DEPENDENCY); BLOCK_RECORD(input_block, DEPENDENCY_DIRECTORY); BLOCK_RECORD(input_block, MODULE_INTERFACE_PATH); BLOCK_RECORD(input_block, IMPORTED_MODULE_SPIS); BLOCK(DECLS_AND_TYPES_BLOCK); #define RECORD(X) BLOCK_RECORD(decls_block, X); #include "DeclTypeRecordNodes.def" BLOCK(IDENTIFIER_DATA_BLOCK); BLOCK_RECORD(identifier_block, IDENTIFIER_DATA); BLOCK(INDEX_BLOCK); BLOCK_RECORD(index_block, TYPE_OFFSETS); BLOCK_RECORD(index_block, DECL_OFFSETS); BLOCK_RECORD(index_block, IDENTIFIER_OFFSETS); BLOCK_RECORD(index_block, TOP_LEVEL_DECLS); BLOCK_RECORD(index_block, OPERATORS); BLOCK_RECORD(index_block, EXTENSIONS); BLOCK_RECORD(index_block, CLASS_MEMBERS_FOR_DYNAMIC_LOOKUP); BLOCK_RECORD(index_block, OPERATOR_METHODS); BLOCK_RECORD(index_block, OBJC_METHODS); BLOCK_RECORD(index_block, DERIVATIVE_FUNCTION_CONFIGURATIONS); BLOCK_RECORD(index_block, ENTRY_POINT); BLOCK_RECORD(index_block, LOCAL_DECL_CONTEXT_OFFSETS); BLOCK_RECORD(index_block, GENERIC_SIGNATURE_OFFSETS); BLOCK_RECORD(index_block, SUBSTITUTION_MAP_OFFSETS); BLOCK_RECORD(index_block, CLANG_TYPE_OFFSETS); BLOCK_RECORD(index_block, LOCAL_TYPE_DECLS); BLOCK_RECORD(index_block, NORMAL_CONFORMANCE_OFFSETS); BLOCK_RECORD(index_block, SIL_LAYOUT_OFFSETS); BLOCK_RECORD(index_block, PRECEDENCE_GROUPS); BLOCK_RECORD(index_block, NESTED_TYPE_DECLS); BLOCK_RECORD(index_block, DECL_MEMBER_NAMES); BLOCK_RECORD(index_block, DECL_FINGERPRINTS); BLOCK_RECORD(index_block, ORDERED_TOP_LEVEL_DECLS); BLOCK_RECORD(index_block, EXPORTED_PRESPECIALIZATION_DECLS); BLOCK(DECL_MEMBER_TABLES_BLOCK); BLOCK_RECORD(decl_member_tables_block, DECL_MEMBERS); BLOCK(SIL_BLOCK); BLOCK_RECORD(sil_block, SIL_FUNCTION); BLOCK_RECORD(sil_block, SIL_BASIC_BLOCK); BLOCK_RECORD(sil_block, SIL_ONE_VALUE_ONE_OPERAND); BLOCK_RECORD(sil_block, SIL_ONE_TYPE); BLOCK_RECORD(sil_block, SIL_ONE_OPERAND); BLOCK_RECORD(sil_block, SIL_ONE_TYPE_ONE_OPERAND); BLOCK_RECORD(sil_block, SIL_ONE_TYPE_VALUES); BLOCK_RECORD(sil_block, SIL_TWO_OPERANDS); BLOCK_RECORD(sil_block, SIL_TAIL_ADDR); BLOCK_RECORD(sil_block, SIL_INST_APPLY); BLOCK_RECORD(sil_block, SIL_INST_NO_OPERAND); BLOCK_RECORD(sil_block, SIL_VTABLE); BLOCK_RECORD(sil_block, SIL_VTABLE_ENTRY); BLOCK_RECORD(sil_block, SIL_GLOBALVAR); BLOCK_RECORD(sil_block, SIL_INIT_EXISTENTIAL); BLOCK_RECORD(sil_block, SIL_WITNESS_TABLE); BLOCK_RECORD(sil_block, SIL_WITNESS_METHOD_ENTRY); BLOCK_RECORD(sil_block, SIL_WITNESS_BASE_ENTRY); BLOCK_RECORD(sil_block, SIL_WITNESS_ASSOC_PROTOCOL); BLOCK_RECORD(sil_block, SIL_WITNESS_ASSOC_ENTRY); BLOCK_RECORD(sil_block, SIL_WITNESS_CONDITIONAL_CONFORMANCE); BLOCK_RECORD(sil_block, SIL_DEFAULT_WITNESS_TABLE); BLOCK_RECORD(sil_block, SIL_DEFAULT_WITNESS_TABLE_NO_ENTRY); BLOCK_RECORD(sil_block, SIL_INST_WITNESS_METHOD); BLOCK_RECORD(sil_block, SIL_SPECIALIZE_ATTR); BLOCK_RECORD(sil_block, SIL_ONE_OPERAND_EXTRA_ATTR); BLOCK_RECORD(sil_block, SIL_TWO_OPERANDS_EXTRA_ATTR); // These layouts can exist in both decl blocks and sil blocks. #define BLOCK_RECORD_WITH_NAMESPACE(K, X) emitRecordID(X, #X, nameBuffer) BLOCK_RECORD_WITH_NAMESPACE(sil_block, decls_block::INVALID_PROTOCOL_CONFORMANCE); BLOCK_RECORD_WITH_NAMESPACE(sil_block, decls_block::ABSTRACT_PROTOCOL_CONFORMANCE); BLOCK_RECORD_WITH_NAMESPACE(sil_block, decls_block::NORMAL_PROTOCOL_CONFORMANCE); BLOCK_RECORD_WITH_NAMESPACE(sil_block, decls_block::SELF_PROTOCOL_CONFORMANCE); BLOCK_RECORD_WITH_NAMESPACE(sil_block, decls_block::SPECIALIZED_PROTOCOL_CONFORMANCE); BLOCK_RECORD_WITH_NAMESPACE(sil_block, decls_block::INHERITED_PROTOCOL_CONFORMANCE); BLOCK_RECORD_WITH_NAMESPACE(sil_block, decls_block::NORMAL_PROTOCOL_CONFORMANCE_ID); BLOCK_RECORD_WITH_NAMESPACE(sil_block, decls_block::PROTOCOL_CONFORMANCE_XREF); BLOCK_RECORD_WITH_NAMESPACE(sil_block, decls_block::GENERIC_PARAM_LIST); BLOCK_RECORD_WITH_NAMESPACE(sil_block, decls_block::GENERIC_REQUIREMENT); BLOCK_RECORD_WITH_NAMESPACE(sil_block, decls_block::LAYOUT_REQUIREMENT); BLOCK(SIL_INDEX_BLOCK); BLOCK_RECORD(sil_index_block, SIL_FUNC_NAMES); BLOCK_RECORD(sil_index_block, SIL_FUNC_OFFSETS); BLOCK_RECORD(sil_index_block, SIL_VTABLE_NAMES); BLOCK_RECORD(sil_index_block, SIL_VTABLE_OFFSETS); BLOCK_RECORD(sil_index_block, SIL_GLOBALVAR_NAMES); BLOCK_RECORD(sil_index_block, SIL_GLOBALVAR_OFFSETS); BLOCK_RECORD(sil_index_block, SIL_WITNESS_TABLE_NAMES); BLOCK_RECORD(sil_index_block, SIL_WITNESS_TABLE_OFFSETS); BLOCK_RECORD(sil_index_block, SIL_DEFAULT_WITNESS_TABLE_NAMES); BLOCK_RECORD(sil_index_block, SIL_DEFAULT_WITNESS_TABLE_OFFSETS); BLOCK_RECORD(sil_index_block, SIL_PROPERTY_OFFSETS); BLOCK_RECORD(sil_index_block, SIL_DIFFERENTIABILITY_WITNESS_NAMES); BLOCK_RECORD(sil_index_block, SIL_DIFFERENTIABILITY_WITNESS_OFFSETS); BLOCK(INCREMENTAL_INFORMATION_BLOCK); BLOCK_RECORD(fine_grained_dependencies::record_block, METADATA); BLOCK_RECORD(fine_grained_dependencies::record_block, SOURCE_FILE_DEP_GRAPH_NODE); BLOCK_RECORD(fine_grained_dependencies::record_block, FINGERPRINT_NODE); BLOCK_RECORD(fine_grained_dependencies::record_block, DEPENDS_ON_DEFINITION_NODE); BLOCK_RECORD(fine_grained_dependencies::record_block, IDENTIFIER_NODE); #undef BLOCK #undef BLOCK_RECORD } void Serializer::writeHeader(const SerializationOptions &options) { { BCBlockRAII restoreBlock(Out, CONTROL_BLOCK_ID, 3); control_block::ModuleNameLayout ModuleName(Out); control_block::MetadataLayout Metadata(Out); control_block::TargetLayout Target(Out); ModuleName.emit(ScratchRecord, M->getName().str()); SmallString<32> versionStringBuf; llvm::raw_svector_ostream versionString(versionStringBuf); versionString << Version::getCurrentLanguageVersion(); size_t shortVersionStringLength = versionString.tell(); versionString << '(' << M->getASTContext().LangOpts.EffectiveLanguageVersion; size_t compatibilityVersionStringLength = versionString.tell() - shortVersionStringLength - 1; versionString << ")/" << version::getSwiftFullVersion(); auto userModuleMajor = options.UserModuleVersion.getMajor(); auto userModuleMinor = 0; if (auto minor = options.UserModuleVersion.getMinor()) { userModuleMinor = *minor; } auto userModuleSubminor = 0; if (auto subMinor = options.UserModuleVersion.getSubminor()) { userModuleSubminor = *subMinor; } auto userModuleBuild = 0; if (auto build = options.UserModuleVersion.getBuild()) { userModuleBuild = *build; } Metadata.emit(ScratchRecord, SWIFTMODULE_VERSION_MAJOR, SWIFTMODULE_VERSION_MINOR, shortVersionStringLength, compatibilityVersionStringLength, userModuleMajor, userModuleMinor, userModuleSubminor, userModuleBuild, versionString.str()); Target.emit(ScratchRecord, M->getASTContext().LangOpts.Target.str()); { llvm::BCBlockRAII restoreBlock(Out, OPTIONS_BLOCK_ID, 4); options_block::IsSIBLayout IsSIB(Out); IsSIB.emit(ScratchRecord, options.IsSIB); if (options.StaticLibrary) { options_block::IsStaticLibraryLayout IsStaticLibrary(Out); IsStaticLibrary.emit(ScratchRecord); } if (M->isTestingEnabled()) { options_block::IsTestableLayout IsTestable(Out); IsTestable.emit(ScratchRecord); } if (M->arePrivateImportsEnabled()) { options_block::ArePrivateImportsEnabledLayout PrivateImports(Out); PrivateImports.emit(ScratchRecord); } if (M->isImplicitDynamicEnabled()) { options_block::IsImplicitDynamicEnabledLayout ImplicitDynamic(Out); ImplicitDynamic.emit(ScratchRecord); } if (M->getResilienceStrategy() != ResilienceStrategy::Default) { options_block::ResilienceStrategyLayout Strategy(Out); Strategy.emit(ScratchRecord, unsigned(M->getResilienceStrategy())); } if (allowCompilerErrors()) { options_block::IsAllowModuleWithCompilerErrorsEnabledLayout AllowErrors(Out); AllowErrors.emit(ScratchRecord); } if (M->getABIName() != M->getName()) { options_block::ModuleABINameLayout ABIName(Out); ABIName.emit(ScratchRecord, M->getABIName().str()); } if (options.SerializeOptionsForDebugging) { options_block::SDKPathLayout SDKPath(Out); options_block::XCCLayout XCC(Out); SDKPath.emit(ScratchRecord, M->getASTContext().SearchPathOpts.SDKPath); auto &Opts = options.ExtraClangOptions; for (auto Arg = Opts.begin(), E = Opts.end(); Arg != E; ++Arg) { // FIXME: This is a hack and calls for a better design. // // Filter out any -ivfsoverlay options that include an // unextended-module-overlay.yaml overlay. By convention the Xcode // buildsystem uses these while *building* mixed Objective-C and Swift // frameworks; but they should never be used to *import* the module // defined in the framework. if (StringRef(*Arg).startswith("-ivfsoverlay")) { auto Next = std::next(Arg); if (Next != E && StringRef(*Next).endswith("unextended-module-overlay.yaml")) { ++Arg; continue; } } XCC.emit(ScratchRecord, *Arg); } } } } } static void flattenImportPath(const ImportedModule &import, SmallVectorImpl &out) { llvm::raw_svector_ostream outStream(out); import.importedModule->getReverseFullModuleName().printForward( outStream, StringRef("\0", 1)); if (import.accessPath.empty()) return; outStream << '\0'; assert(import.accessPath.size() == 1 && "can only handle top-level decl imports"); auto accessPathElem = import.accessPath.front(); outStream << accessPathElem.Item.str(); } uint64_t getRawModTimeOrHash(const SerializationOptions::FileDependency &dep) { if (dep.isHashBased()) return dep.getContentHash(); return dep.getModificationTime(); } using ImportSet = llvm::SmallSet; static ImportSet getImportsAsSet(const ModuleDecl *M, ModuleDecl::ImportFilter filter) { SmallVector imports; M->getImportedModules(imports, filter); ImportSet importSet; importSet.insert(imports.begin(), imports.end()); return importSet; } void Serializer::writeInputBlock(const SerializationOptions &options) { BCBlockRAII restoreBlock(Out, INPUT_BLOCK_ID, 4); input_block::ImportedModuleLayout importedModule(Out); input_block::ImportedModuleLayoutSPI ImportedModuleSPI(Out); input_block::LinkLibraryLayout LinkLibrary(Out); input_block::ImportedHeaderLayout ImportedHeader(Out); input_block::ImportedHeaderContentsLayout ImportedHeaderContents(Out); input_block::SearchPathLayout SearchPath(Out); input_block::FileDependencyLayout FileDependency(Out); input_block::DependencyDirectoryLayout DependencyDirectory(Out); input_block::ModuleInterfaceLayout ModuleInterface(Out); if (options.SerializeOptionsForDebugging) { const SearchPathOptions &searchPathOpts = M->getASTContext().SearchPathOpts; // Put the framework search paths first so that they'll be preferred upon // deserialization. for (auto &framepath : searchPathOpts.FrameworkSearchPaths) SearchPath.emit(ScratchRecord, /*framework=*/true, framepath.IsSystem, framepath.Path); for (auto &path : searchPathOpts.ImportSearchPaths) SearchPath.emit(ScratchRecord, /*framework=*/false, /*system=*/false, path); } // Note: We're not using StringMap here because we don't need to own the // strings. llvm::DenseMap dependencyDirectories; for (auto const &dep : options.Dependencies) { StringRef directoryName = llvm::sys::path::parent_path(dep.getPath()); unsigned &dependencyDirectoryIndex = dependencyDirectories[directoryName]; if (!dependencyDirectoryIndex) { // This name must be newly-added. Give it a new ID (and skip 0). dependencyDirectoryIndex = dependencyDirectories.size(); DependencyDirectory.emit(ScratchRecord, directoryName); } FileDependency.emit(ScratchRecord, dep.getSize(), getRawModTimeOrHash(dep), dep.isHashBased(), dep.isSDKRelative(), dependencyDirectoryIndex, llvm::sys::path::filename(dep.getPath())); } if (!options.ModuleInterface.empty()) ModuleInterface.emit(ScratchRecord, options.ModuleInterface); SmallVector allImports; M->getImportedModules(allImports, {ModuleDecl::ImportFilterKind::Exported, ModuleDecl::ImportFilterKind::Default, ModuleDecl::ImportFilterKind::ImplementationOnly, ModuleDecl::ImportFilterKind::SPIAccessControl}); ImportedModule::removeDuplicates(allImports); // Collect the public and private imports as a subset so that we can // distinguish them. ImportSet publicImportSet = getImportsAsSet(M, ModuleDecl::ImportFilterKind::Exported); ImportSet privateImportSet = getImportsAsSet(M, ModuleDecl::ImportFilterKind::Default); ImportSet spiImportSet = getImportsAsSet(M, ModuleDecl::ImportFilterKind::SPIAccessControl); auto clangImporter = static_cast(M->getASTContext().getClangModuleLoader()); ModuleDecl *bridgingHeaderModule = clangImporter->getImportedHeaderModule(); ImportedModule bridgingHeaderImport{ImportPath::Access(), bridgingHeaderModule}; // Make sure the bridging header module is always at the top of the import // list, mimicking how it is processed before any module imports when // compiling source files. if (llvm::is_contained(allImports, bridgingHeaderImport)) { off_t importedHeaderSize = 0; time_t importedHeaderModTime = 0; std::string contents; if (!options.ImportedHeader.empty()) { contents = clangImporter->getBridgingHeaderContents( options.ImportedHeader, importedHeaderSize, importedHeaderModTime); } assert(publicImportSet.count(bridgingHeaderImport)); ImportedHeader.emit(ScratchRecord, publicImportSet.count(bridgingHeaderImport), importedHeaderSize, importedHeaderModTime, options.ImportedHeader); if (!contents.empty()) { contents.push_back('\0'); ImportedHeaderContents.emit(ScratchRecord, contents); } } ModuleDecl *theBuiltinModule = M->getASTContext().TheBuiltinModule; for (auto import : allImports) { if (import.importedModule == theBuiltinModule || import.importedModule == bridgingHeaderModule) { continue; } SmallString<64> importPath; flattenImportPath(import, importPath); serialization::ImportControl stableImportControl; // The order of checks here is important, since a module can be imported // differently in different files, and we need to record the "most visible" // form here. if (publicImportSet.count(import)) stableImportControl = ImportControl::Exported; else if (privateImportSet.count(import) || spiImportSet.count(import)) stableImportControl = ImportControl::Normal; else stableImportControl = ImportControl::ImplementationOnly; llvm::SmallSetVector spis; M->lookupImportedSPIGroups(import.importedModule, spis); importedModule.emit(ScratchRecord, static_cast(stableImportControl), !import.accessPath.empty(), !spis.empty(), importPath); if (!spis.empty()) { SmallString<64> out; llvm::raw_svector_ostream outStream(out); llvm::interleave( spis, [&outStream](Identifier next) { outStream << next.str(); }, [&outStream] { outStream << StringRef("\0", 1); }); ImportedModuleSPI.emit(ScratchRecord, out); } } if (!options.ModuleLinkName.empty()) { LinkLibrary.emit(ScratchRecord, serialization::LibraryKind::Library, options.AutolinkForceLoad, options.ModuleLinkName); } } /// Translate AST default argument kind to the Serialization enum values, which /// are guaranteed to be stable. static uint8_t getRawStableDefaultArgumentKind(swift::DefaultArgumentKind kind) { switch (kind) { #define CASE(X) \ case swift::DefaultArgumentKind::X: \ return static_cast(serialization::DefaultArgumentKind::X); CASE(None) CASE(Normal) CASE(Inherited) CASE(Column) CASE(FileID) CASE(FilePath) CASE(FileIDSpelledAsFile) CASE(FilePathSpelledAsFile) CASE(Line) CASE(Function) CASE(DSOHandle) CASE(NilLiteral) CASE(EmptyArray) CASE(EmptyDictionary) CASE(StoredProperty) #undef CASE } llvm_unreachable("Unhandled DefaultArgumentKind in switch."); } static uint8_t getRawStableMetatypeRepresentation(const AnyMetatypeType *metatype) { if (!metatype->hasRepresentation()) { return serialization::MetatypeRepresentation::MR_None; } switch (metatype->getRepresentation()) { case swift::MetatypeRepresentation::Thin: return serialization::MetatypeRepresentation::MR_Thin; case swift::MetatypeRepresentation::Thick: return serialization::MetatypeRepresentation::MR_Thick; case swift::MetatypeRepresentation::ObjC: return serialization::MetatypeRepresentation::MR_ObjC; } llvm_unreachable("bad representation"); } /// Translate from the requirement kind to the Serialization enum /// values, which are guaranteed to be stable. static uint8_t getRawStableRequirementKind(RequirementKind kind) { #define CASE(KIND) \ case RequirementKind::KIND: \ return GenericRequirementKind::KIND; switch (kind) { CASE(Conformance) CASE(Superclass) CASE(SameType) CASE(Layout) } #undef CASE llvm_unreachable("Unhandled RequirementKind in switch."); } void Serializer::writeGenericRequirements(ArrayRef requirements, const std::array &abbrCodes) { using namespace decls_block; if (requirements.empty()) return; auto reqAbbrCode = abbrCodes[GenericRequirementLayout::Code]; auto layoutReqAbbrCode = abbrCodes[LayoutRequirementLayout::Code]; for (const auto &req : requirements) { if (req.getKind() != RequirementKind::Layout) GenericRequirementLayout::emitRecord( Out, ScratchRecord, reqAbbrCode, getRawStableRequirementKind(req.getKind()), addTypeRef(req.getFirstType()), addTypeRef(req.getSecondType())); else { // Write layout requirement. auto layout = req.getLayoutConstraint(); unsigned size = 0; unsigned alignment = 0; if (layout->isKnownSizeTrivial()) { size = layout->getTrivialSizeInBits(); alignment = layout->getAlignmentInBits(); } LayoutRequirementKind rawKind = LayoutRequirementKind::UnknownLayout; switch (layout->getKind()) { case LayoutConstraintKind::NativeRefCountedObject: rawKind = LayoutRequirementKind::NativeRefCountedObject; break; case LayoutConstraintKind::RefCountedObject: rawKind = LayoutRequirementKind::RefCountedObject; break; case LayoutConstraintKind::Trivial: rawKind = LayoutRequirementKind::Trivial; break; case LayoutConstraintKind::TrivialOfExactSize: rawKind = LayoutRequirementKind::TrivialOfExactSize; break; case LayoutConstraintKind::TrivialOfAtMostSize: rawKind = LayoutRequirementKind::TrivialOfAtMostSize; break; case LayoutConstraintKind::Class: rawKind = LayoutRequirementKind::Class; break; case LayoutConstraintKind::NativeClass: rawKind = LayoutRequirementKind::NativeClass; break; case LayoutConstraintKind::UnknownLayout: rawKind = LayoutRequirementKind::UnknownLayout; break; } LayoutRequirementLayout::emitRecord( Out, ScratchRecord, layoutReqAbbrCode, rawKind, addTypeRef(req.getFirstType()), size, alignment); } } } void Serializer::writeASTBlockEntity(GenericSignature sig) { using namespace decls_block; assert(sig); assert(GenericSignaturesToSerialize.hasRef(sig)); // Determine whether we can just write the param types as is, or whether we // have to encode them manually because one of them has a declaration with // module context (which can happen in SIL). bool mustEncodeParamsManually = llvm::any_of(sig->getGenericParams(), [](const GenericTypeParamType *paramTy) { auto *decl = paramTy->getDecl(); return decl && decl->getDeclContext()->isModuleScopeContext(); }); if (!mustEncodeParamsManually) { // Record the generic parameters. SmallVector rawParamIDs; for (auto *paramTy : sig->getGenericParams()) { rawParamIDs.push_back(addTypeRef(paramTy)); } auto abbrCode = DeclTypeAbbrCodes[GenericSignatureLayout::Code]; GenericSignatureLayout::emitRecord(Out, ScratchRecord, abbrCode, rawParamIDs); } else { // Record the generic parameters. SmallVector rawParamIDs; for (auto *paramTy : sig->getGenericParams()) { auto *decl = paramTy->getDecl(); // For a full environment, add the name and canonicalize the param type. Identifier paramName = decl ? decl->getName() : Identifier(); rawParamIDs.push_back(addDeclBaseNameRef(paramName)); paramTy = paramTy->getCanonicalType()->castTo(); rawParamIDs.push_back(addTypeRef(paramTy)); } auto envAbbrCode = DeclTypeAbbrCodes[SILGenericSignatureLayout::Code]; SILGenericSignatureLayout::emitRecord(Out, ScratchRecord, envAbbrCode, rawParamIDs); } writeGenericRequirements(sig->getRequirements(), DeclTypeAbbrCodes); } void Serializer::writeASTBlockEntity(const SubstitutionMap substitutions) { using namespace decls_block; assert(substitutions); assert(SubstitutionMapsToSerialize.hasRef(substitutions)); // Collect the replacement types. SmallVector rawReplacementTypes; for (auto type : substitutions.getReplacementTypes()) rawReplacementTypes.push_back(addTypeRef(type)); auto substitutionsAbbrCode = DeclTypeAbbrCodes[SubstitutionMapLayout::Code]; SubstitutionMapLayout::emitRecord(Out, ScratchRecord, substitutionsAbbrCode, addGenericSignatureRef( substitutions.getGenericSignature()), substitutions.getConformances().size(), rawReplacementTypes); writeConformances(substitutions.getConformances(), DeclTypeAbbrCodes); } void Serializer::writeASTBlockEntity(const SILLayout *layout) { using namespace decls_block; assert(SILLayoutsToSerialize.hasRef(layout)); SmallVector data; // Save field types. for (auto &field : layout->getFields()) { unsigned typeRef = addTypeRef(field.getLoweredType()); // Set the high bit if mutable. if (field.isMutable()) typeRef |= 0x80000000U; data.push_back(typeRef); } unsigned abbrCode = DeclTypeAbbrCodes[SILLayoutLayout::Code]; SILLayoutLayout::emitRecord( Out, ScratchRecord, abbrCode, addGenericSignatureRef(layout->getGenericSignature()), layout->getFields().size(), data); } void Serializer::writeASTBlockEntity( const NormalProtocolConformance *conformance) { using namespace decls_block; // The conformance must be complete, or we can't serialize it. assert(conformance->isComplete() || allowCompilerErrors()); assert(NormalConformancesToSerialize.hasRef(conformance)); auto protocol = conformance->getProtocol(); SmallVector data; unsigned numValueWitnesses = 0; unsigned numTypeWitnesses = 0; conformance->forEachTypeWitness([&](AssociatedTypeDecl *assocType, Type type, TypeDecl *typeDecl) { data.push_back(addDeclRef(assocType)); data.push_back(addTypeRef(type)); data.push_back(addDeclRef(typeDecl, /*allowTypeAliasXRef*/true)); ++numTypeWitnesses; return false; }); conformance->forEachValueWitness([&](ValueDecl *req, Witness witness) { ++numValueWitnesses; data.push_back(addDeclRef(req)); data.push_back(addDeclRef(witness.getDecl())); assert(witness.getDecl() || req->getAttrs().hasAttribute() || req->getAttrs().isUnavailable(req->getASTContext()) || allowCompilerErrors()); // If there is no witness, we're done. if (!witness.getDecl()) return; auto subs = witness.getSubstitutions(); // Canonicalize away typealiases, since these substitutions aren't used // for diagnostics and we reference fewer declarations that way. subs = subs.getCanonical(); // Map archetypes to type parameters, since we always substitute them // away. Note that in a merge-modules pass, we're serializing conformances // that we deserialized, so they will already have their replacement types // in terms of interface types; hence the hasArchetypes() check is // necessary for correctness, not just as a fast path. if (subs.hasArchetypes()) subs = subs.mapReplacementTypesOutOfContext(); data.push_back(addSubstitutionMapRef(subs)); }); unsigned numSignatureConformances = conformance->getSignatureConformances().size(); unsigned abbrCode = DeclTypeAbbrCodes[NormalProtocolConformanceLayout::Code]; auto ownerID = addDeclContextRef(conformance->getDeclContext()); NormalProtocolConformanceLayout::emitRecord(Out, ScratchRecord, abbrCode, addDeclRef(protocol), ownerID.getOpaqueValue(), numTypeWitnesses, numValueWitnesses, numSignatureConformances, data); // Write requirement signature conformances. for (auto reqConformance : conformance->getSignatureConformances()) writeConformance(reqConformance, DeclTypeAbbrCodes); } void Serializer::writeConformance(ProtocolConformance *conformance, const std::array &abbrCodes, GenericEnvironment *genericEnv) { writeConformance(ProtocolConformanceRef(conformance), abbrCodes, genericEnv); } void Serializer::writeConformance(ProtocolConformanceRef conformanceRef, const std::array &abbrCodes, GenericEnvironment *genericEnv) { using namespace decls_block; if (conformanceRef.isInvalid()) { unsigned abbrCode = abbrCodes[InvalidProtocolConformanceLayout::Code]; InvalidProtocolConformanceLayout::emitRecord(Out, ScratchRecord, abbrCode); return; } if (conformanceRef.isAbstract()) { unsigned abbrCode = abbrCodes[AbstractProtocolConformanceLayout::Code]; AbstractProtocolConformanceLayout::emitRecord(Out, ScratchRecord, abbrCode, addDeclRef(conformanceRef.getAbstract())); return; } auto conformance = conformanceRef.getConcrete(); switch (conformance->getKind()) { case ProtocolConformanceKind::Normal: { auto normal = cast(conformance); if (!isDeclXRef(normal->getDeclContext()->getAsDecl()) && !isa(normal->getDeclContext() ->getModuleScopeContext())) { // A normal conformance in this module file. unsigned abbrCode = abbrCodes[NormalProtocolConformanceIdLayout::Code]; NormalProtocolConformanceIdLayout::emitRecord(Out, ScratchRecord, abbrCode, addConformanceRef(normal)); } else { // A conformance in a different module file. unsigned abbrCode = abbrCodes[ProtocolConformanceXrefLayout::Code]; ProtocolConformanceXrefLayout::emitRecord( Out, ScratchRecord, abbrCode, addDeclRef(normal->getProtocol()), addDeclRef(normal->getType()->getAnyNominal()), addContainingModuleRef(normal->getDeclContext())); } break; } case ProtocolConformanceKind::Self: { auto self = cast(conformance); unsigned abbrCode = abbrCodes[SelfProtocolConformanceLayout::Code]; auto protocolID = addDeclRef(self->getProtocol()); SelfProtocolConformanceLayout::emitRecord(Out, ScratchRecord, abbrCode, protocolID); break; } case ProtocolConformanceKind::Specialized: { auto conf = cast(conformance); unsigned abbrCode = abbrCodes[SpecializedProtocolConformanceLayout::Code]; auto type = conf->getType(); if (genericEnv && type->hasArchetype()) type = type->mapTypeOutOfContext(); SpecializedProtocolConformanceLayout::emitRecord( Out, ScratchRecord, abbrCode, addTypeRef(type), addSubstitutionMapRef(conf->getSubstitutionMap())); writeConformance(conf->getGenericConformance(), abbrCodes, genericEnv); break; } case ProtocolConformanceKind::Inherited: { auto conf = cast(conformance); unsigned abbrCode = abbrCodes[InheritedProtocolConformanceLayout::Code]; auto type = conf->getType(); if (genericEnv && type->hasArchetype()) type = type->mapTypeOutOfContext(); InheritedProtocolConformanceLayout::emitRecord( Out, ScratchRecord, abbrCode, addTypeRef(type)); writeConformance(conf->getInheritedConformance(), abbrCodes, genericEnv); break; } } } void Serializer::writeConformances(ArrayRef conformances, const std::array &abbrCodes) { using namespace decls_block; for (auto conformance : conformances) writeConformance(conformance, abbrCodes); } void Serializer::writeConformances(ArrayRef conformances, const std::array &abbrCodes) { using namespace decls_block; for (auto conformance : conformances) writeConformance(conformance, abbrCodes); } static bool shouldSerializeMember(Decl *D) { switch (D->getKind()) { case DeclKind::Import: case DeclKind::InfixOperator: case DeclKind::PrefixOperator: case DeclKind::PostfixOperator: case DeclKind::TopLevelCode: case DeclKind::Extension: case DeclKind::Module: case DeclKind::PrecedenceGroup: if (D->getASTContext().LangOpts.AllowModuleWithCompilerErrors) return false; llvm_unreachable("decl should never be a member"); case DeclKind::MissingMember: if (D->getASTContext().LangOpts.AllowModuleWithCompilerErrors) return false; llvm_unreachable("should never need to reserialize a member placeholder"); case DeclKind::IfConfig: case DeclKind::PoundDiagnostic: return false; case DeclKind::EnumCase: return false; case DeclKind::OpaqueType: return true; case DeclKind::EnumElement: case DeclKind::Protocol: case DeclKind::Constructor: case DeclKind::Destructor: case DeclKind::PatternBinding: case DeclKind::Subscript: case DeclKind::TypeAlias: case DeclKind::GenericTypeParam: case DeclKind::AssociatedType: case DeclKind::Enum: case DeclKind::Struct: case DeclKind::Class: case DeclKind::Var: case DeclKind::Param: case DeclKind::Func: case DeclKind::Accessor: return true; } llvm_unreachable("Unhandled DeclKind in switch."); } static serialization::AccessorKind getStableAccessorKind(swift::AccessorKind K){ switch (K) { #define ACCESSOR(ID) \ case swift::AccessorKind::ID: return serialization::ID; #include "swift/AST/AccessorKinds.def" } llvm_unreachable("Unhandled AccessorKind in switch."); } static serialization::CtorInitializerKind getStableCtorInitializerKind(swift::CtorInitializerKind K){ switch (K) { #define CASE(NAME) \ case swift::CtorInitializerKind::NAME: return serialization::NAME; CASE(Designated) CASE(Convenience) CASE(Factory) CASE(ConvenienceFactory) #undef CASE } llvm_unreachable("Unhandled CtorInitializerKind in switch."); } static serialization::ClangDeclPathComponentKind getStableClangDeclPathComponentKind( StableSerializationPath::ExternalPath::ComponentKind kind) { switch (kind) { #define CASE(ID) \ case StableSerializationPath::ExternalPath::ID: \ return serialization::ClangDeclPathComponentKind::ID; CASE(Record) CASE(Enum) CASE(Namespace) CASE(Typedef) CASE(TypedefAnonDecl) CASE(ObjCInterface) CASE(ObjCProtocol) #undef CASE } llvm_unreachable("bad kind"); } void Serializer::writeCrossReference(const DeclContext *DC, uint32_t pathLen) { using namespace decls_block; unsigned abbrCode; switch (DC->getContextKind()) { case DeclContextKind::AbstractClosureExpr: case DeclContextKind::Initializer: case DeclContextKind::TopLevelCodeDecl: case DeclContextKind::SerializedLocal: case DeclContextKind::EnumElementDecl: llvm_unreachable("cannot cross-reference this context"); case DeclContextKind::Module: llvm_unreachable("should only cross-reference something within a file"); case DeclContextKind::FileUnit: abbrCode = DeclTypeAbbrCodes[XRefLayout::Code]; XRefLayout::emitRecord(Out, ScratchRecord, abbrCode, addContainingModuleRef(DC), pathLen); break; case DeclContextKind::GenericTypeDecl: { auto generic = cast(DC); writeCrossReference(DC->getParent(), pathLen + 1); // Opaque return types are unnamed and need a special xref. if (auto opaque = dyn_cast(generic)) { if (!opaque->hasName()) { abbrCode = DeclTypeAbbrCodes[XRefOpaqueReturnTypePathPieceLayout::Code]; XRefOpaqueReturnTypePathPieceLayout::emitRecord(Out, ScratchRecord, abbrCode, addDeclBaseNameRef(opaque->getOpaqueReturnTypeIdentifier())); break; } } assert(generic->hasName()); abbrCode = DeclTypeAbbrCodes[XRefTypePathPieceLayout::Code]; Identifier discriminator; if (generic->isOutermostPrivateOrFilePrivateScope()) { auto *containingFile = cast(generic->getModuleScopeContext()); discriminator = containingFile->getDiscriminatorForPrivateValue(generic); } bool isProtocolExt = DC->getParent()->getExtendedProtocolDecl(); XRefTypePathPieceLayout::emitRecord(Out, ScratchRecord, abbrCode, addDeclBaseNameRef(generic->getName()), addDeclBaseNameRef(discriminator), isProtocolExt, generic->hasClangNode()); break; } case DeclContextKind::ExtensionDecl: { auto ext = cast(DC); auto nominal = ext->getExtendedNominal(); assert(nominal); writeCrossReference(nominal, pathLen + 1); abbrCode = DeclTypeAbbrCodes[XRefExtensionPathPieceLayout::Code]; CanGenericSignature genericSig(nullptr); if (ext->isConstrainedExtension()) { genericSig = ext->getGenericSignature().getCanonicalSignature(); } XRefExtensionPathPieceLayout::emitRecord( Out, ScratchRecord, abbrCode, addContainingModuleRef(DC), addGenericSignatureRef(genericSig)); break; } case DeclContextKind::SubscriptDecl: { auto SD = cast(DC); writeCrossReference(DC->getParent(), pathLen + 1); Type ty = SD->getInterfaceType()->getCanonicalType(); abbrCode = DeclTypeAbbrCodes[XRefValuePathPieceLayout::Code]; bool isProtocolExt = SD->getDeclContext()->getExtendedProtocolDecl(); XRefValuePathPieceLayout::emitRecord(Out, ScratchRecord, abbrCode, addTypeRef(ty), SUBSCRIPT_ID, isProtocolExt, SD->hasClangNode(), SD->isStatic()); break; } case DeclContextKind::AbstractFunctionDecl: { if (auto fn = dyn_cast(DC)) { auto storage = fn->getStorage(); writeCrossReference(storage->getDeclContext(), pathLen + 2); Type ty = storage->getInterfaceType()->getCanonicalType(); IdentifierID nameID = addDeclBaseNameRef(storage->getBaseName()); bool isProtocolExt = fn->getDeclContext()->getExtendedProtocolDecl(); abbrCode = DeclTypeAbbrCodes[XRefValuePathPieceLayout::Code]; XRefValuePathPieceLayout::emitRecord(Out, ScratchRecord, abbrCode, addTypeRef(ty), nameID, isProtocolExt, storage->hasClangNode(), storage->isStatic()); abbrCode = DeclTypeAbbrCodes[XRefOperatorOrAccessorPathPieceLayout::Code]; auto emptyID = addDeclBaseNameRef(Identifier()); auto accessorKind = getStableAccessorKind(fn->getAccessorKind()); assert(!fn->isObservingAccessor() && "cannot form cross-reference to observing accessors"); XRefOperatorOrAccessorPathPieceLayout::emitRecord(Out, ScratchRecord, abbrCode, emptyID, accessorKind); break; } auto fn = cast(DC); writeCrossReference(DC->getParent(), pathLen + 1 + fn->isOperator()); Type ty = fn->getInterfaceType()->getCanonicalType(); if (auto ctor = dyn_cast(DC)) { abbrCode = DeclTypeAbbrCodes[XRefInitializerPathPieceLayout::Code]; XRefInitializerPathPieceLayout::emitRecord( Out, ScratchRecord, abbrCode, addTypeRef(ty), (bool)ctor->getDeclContext()->getExtendedProtocolDecl(), ctor->hasClangNode(), getStableCtorInitializerKind(ctor->getInitKind())); break; } abbrCode = DeclTypeAbbrCodes[XRefValuePathPieceLayout::Code]; bool isProtocolExt = fn->getDeclContext()->getExtendedProtocolDecl(); XRefValuePathPieceLayout::emitRecord(Out, ScratchRecord, abbrCode, addTypeRef(ty), addDeclBaseNameRef(fn->getBaseName()), isProtocolExt, fn->hasClangNode(), fn->isStatic()); if (fn->isOperator()) { // Encode the fixity as a filter on the func decls, to distinguish prefix // and postfix operators. auto op = cast(fn)->getOperatorDecl(); assert(op); abbrCode = DeclTypeAbbrCodes[XRefOperatorOrAccessorPathPieceLayout::Code]; auto emptyID = addDeclBaseNameRef(Identifier()); auto fixity = getStableFixity(op->getFixity()); XRefOperatorOrAccessorPathPieceLayout::emitRecord(Out, ScratchRecord, abbrCode, emptyID, fixity); } break; } } } void Serializer::writeCrossReference(const Decl *D) { using namespace decls_block; unsigned abbrCode; if (auto op = dyn_cast(D)) { writeCrossReference(op->getDeclContext(), 1); abbrCode = DeclTypeAbbrCodes[XRefOperatorOrAccessorPathPieceLayout::Code]; auto nameID = addDeclBaseNameRef(op->getName()); auto fixity = getStableFixity(op->getFixity()); XRefOperatorOrAccessorPathPieceLayout::emitRecord(Out, ScratchRecord, abbrCode, nameID, fixity); return; } if (auto prec = dyn_cast(D)) { writeCrossReference(prec->getDeclContext(), 1); abbrCode = DeclTypeAbbrCodes[XRefOperatorOrAccessorPathPieceLayout::Code]; auto nameID = addDeclBaseNameRef(prec->getName()); uint8_t fixity = OperatorKind::PrecedenceGroup; XRefOperatorOrAccessorPathPieceLayout::emitRecord(Out, ScratchRecord, abbrCode, nameID, fixity); return; } if (auto fn = dyn_cast(D)) { // Functions are special because they might be operators. writeCrossReference(fn, 0); return; } writeCrossReference(D->getDeclContext()); if (auto opaque = dyn_cast(D)) { abbrCode = DeclTypeAbbrCodes[XRefOpaqueReturnTypePathPieceLayout::Code]; XRefOpaqueReturnTypePathPieceLayout::emitRecord(Out, ScratchRecord, abbrCode, addDeclBaseNameRef(opaque->getOpaqueReturnTypeIdentifier())); return; } if (auto genericParam = dyn_cast(D)) { assert(!D->getDeclContext()->isModuleScopeContext() && "Cannot cross reference a generic type decl at module scope."); abbrCode = DeclTypeAbbrCodes[XRefGenericParamPathPieceLayout::Code]; XRefGenericParamPathPieceLayout::emitRecord(Out, ScratchRecord, abbrCode, genericParam->getDepth(), genericParam->getIndex()); return; } bool isProtocolExt = D->getDeclContext()->getExtendedProtocolDecl(); if (auto type = dyn_cast(D)) { abbrCode = DeclTypeAbbrCodes[XRefTypePathPieceLayout::Code]; Identifier discriminator; if (type->isOutermostPrivateOrFilePrivateScope()) { auto *containingFile = cast(type->getDeclContext()->getModuleScopeContext()); discriminator = containingFile->getDiscriminatorForPrivateValue(type); } XRefTypePathPieceLayout::emitRecord(Out, ScratchRecord, abbrCode, addDeclBaseNameRef(type->getName()), addDeclBaseNameRef(discriminator), isProtocolExt, D->hasClangNode()); return; } auto val = cast(D); auto ty = val->getInterfaceType()->getCanonicalType(); abbrCode = DeclTypeAbbrCodes[XRefValuePathPieceLayout::Code]; IdentifierID iid = addDeclBaseNameRef(val->getBaseName()); XRefValuePathPieceLayout::emitRecord(Out, ScratchRecord, abbrCode, addTypeRef(ty), iid, isProtocolExt, D->hasClangNode(), val->isStatic()); } /// Translate from the AST associativity enum to the Serialization enum /// values, which are guaranteed to be stable. static uint8_t getRawStableAssociativity(swift::Associativity assoc) { switch (assoc) { case swift::Associativity::Left: return serialization::Associativity::LeftAssociative; case swift::Associativity::Right: return serialization::Associativity::RightAssociative; case swift::Associativity::None: return serialization::Associativity::NonAssociative; } llvm_unreachable("Unhandled Associativity in switch."); } static serialization::StaticSpellingKind getStableStaticSpelling(swift::StaticSpellingKind SS) { switch (SS) { case swift::StaticSpellingKind::None: return serialization::StaticSpellingKind::None; case swift::StaticSpellingKind::KeywordStatic: return serialization::StaticSpellingKind::KeywordStatic; case swift::StaticSpellingKind::KeywordClass: return serialization::StaticSpellingKind::KeywordClass; } llvm_unreachable("Unhandled StaticSpellingKind in switch."); } static uint8_t getRawStableAccessLevel(swift::AccessLevel access) { switch (access) { #define CASE(NAME) \ case swift::AccessLevel::NAME: \ return static_cast(serialization::AccessLevel::NAME); CASE(Private) CASE(FilePrivate) CASE(Internal) CASE(Public) CASE(Open) #undef CASE } llvm_unreachable("Unhandled AccessLevel in switch."); } static serialization::SelfAccessKind getStableSelfAccessKind(swift::SelfAccessKind MM) { switch (MM) { case swift::SelfAccessKind::NonMutating: return serialization::SelfAccessKind::NonMutating; case swift::SelfAccessKind::Mutating: return serialization::SelfAccessKind::Mutating; case swift::SelfAccessKind::Consuming: return serialization::SelfAccessKind::Consuming; } llvm_unreachable("Unhandled StaticSpellingKind in switch."); } #ifndef NDEBUG // This is done with a macro so that we get a slightly more useful assertion. # define DECL(KIND, PARENT)\ LLVM_ATTRIBUTE_UNUSED \ static void verifyAttrSerializable(const KIND ## Decl *D) {\ if (D->Decl::getASTContext().LangOpts.AllowModuleWithCompilerErrors)\ return;\ for (auto Attr : D->getAttrs()) {\ assert(Attr->canAppearOnDecl(D) && "attribute cannot appear on a " #KIND);\ }\ } # include "swift/AST/DeclNodes.def" #else static void verifyAttrSerializable(const Decl *D) {} #endif bool Serializer::isDeclXRef(const Decl *D) const { const DeclContext *topLevel = D->getDeclContext()->getModuleScopeContext(); if (topLevel->getParentModule() != M) return true; if (!SF || topLevel == SF || topLevel == SF->getSynthesizedFile()) return false; // Special-case for SIL generic parameter decls, which don't have a real // DeclContext. if (!isa(topLevel)) { assert(isa(D) && "unexpected decl kind"); return false; } return true; } void Serializer::writePatternBindingInitializer(PatternBindingDecl *binding, unsigned bindingIndex) { using namespace decls_block; auto abbrCode = DeclTypeAbbrCodes[PatternBindingInitializerLayout::Code]; StringRef initStr; SmallString<128> scratch; auto varDecl = binding->getAnchoringVarDecl(bindingIndex); if (binding->hasInitStringRepresentation(bindingIndex) && varDecl->isInitExposedToClients()) { initStr = binding->getInitStringRepresentation(bindingIndex, scratch); } PatternBindingInitializerLayout::emitRecord(Out, ScratchRecord, abbrCode, addDeclRef(binding), bindingIndex, initStr); } void Serializer::writeDefaultArgumentInitializer(const DeclContext *parentContext, unsigned index) { using namespace decls_block; auto abbrCode = DeclTypeAbbrCodes[DefaultArgumentInitializerLayout::Code]; auto parentID = addDeclContextRef(parentContext); DefaultArgumentInitializerLayout::emitRecord(Out, ScratchRecord, abbrCode, parentID.getOpaqueValue(), index); } void Serializer::writeAbstractClosureExpr(const DeclContext *parentContext, Type Ty, bool isImplicit, unsigned discriminator) { using namespace decls_block; auto abbrCode = DeclTypeAbbrCodes[AbstractClosureExprLayout::Code]; auto parentID = addDeclContextRef(parentContext); AbstractClosureExprLayout::emitRecord(Out, ScratchRecord, abbrCode, addTypeRef(Ty), isImplicit, discriminator, parentID.getOpaqueValue()); } void Serializer::writeASTBlockEntity(const DeclContext *DC) { using namespace decls_block; assert(shouldSerializeAsLocalContext(DC) && "should be serialized as a Decl instead"); assert(LocalDeclContextsToSerialize.hasRef(DC)); switch (DC->getContextKind()) { case DeclContextKind::AbstractClosureExpr: { auto ACE = cast(DC); writeAbstractClosureExpr(ACE->getParent(), ACE->getType(), ACE->isImplicit(), ACE->getDiscriminator()); break; } case DeclContextKind::Initializer: { if (auto PBI = dyn_cast(DC)) { writePatternBindingInitializer(PBI->getBinding(), PBI->getBindingIndex()); } else if (auto DAI = dyn_cast(DC)) { writeDefaultArgumentInitializer(DAI->getParent(), DAI->getIndex()); } break; } case DeclContextKind::TopLevelCodeDecl: { auto abbrCode = DeclTypeAbbrCodes[TopLevelCodeDeclContextLayout::Code]; TopLevelCodeDeclContextLayout::emitRecord(Out, ScratchRecord, abbrCode, addDeclContextRef(DC->getParent()).getOpaqueValue()); break; } // If we are merging already serialized modules with local decl contexts, // we handle them here in a similar fashion. case DeclContextKind::SerializedLocal: { auto local = cast(DC); switch (local->getLocalDeclContextKind()) { case LocalDeclContextKind::AbstractClosure: { auto SACE = cast(local); writeAbstractClosureExpr(SACE->getParent(), SACE->getType(), SACE->isImplicit(), SACE->getDiscriminator()); return; } case LocalDeclContextKind::DefaultArgumentInitializer: { auto DAI = cast(local); writeDefaultArgumentInitializer(DAI->getParent(), DAI->getIndex()); return; } case LocalDeclContextKind::PatternBindingInitializer: { auto PBI = cast(local); writePatternBindingInitializer(PBI->getBinding(), PBI->getBindingIndex()); return; } case LocalDeclContextKind::TopLevelCodeDecl: { auto abbrCode = DeclTypeAbbrCodes[TopLevelCodeDeclContextLayout::Code]; TopLevelCodeDeclContextLayout::emitRecord(Out, ScratchRecord, abbrCode, addDeclContextRef(DC->getParent()).getOpaqueValue()); return; } } } default: llvm_unreachable("Trying to write a DeclContext that isn't local"); } } #define SIMPLE_CASE(TYPENAME, VALUE) \ case swift::TYPENAME::VALUE: return uint8_t(serialization::TYPENAME::VALUE); static ForeignErrorConventionKind getRawStableForeignErrorConventionKind( ForeignErrorConvention::Kind kind) { switch (kind) { case ForeignErrorConvention::ZeroResult: return ForeignErrorConventionKind::ZeroResult; case ForeignErrorConvention::NonZeroResult: return ForeignErrorConventionKind::NonZeroResult; case ForeignErrorConvention::ZeroPreservedResult: return ForeignErrorConventionKind::ZeroPreservedResult; case ForeignErrorConvention::NilResult: return ForeignErrorConventionKind::NilResult; case ForeignErrorConvention::NonNilError: return ForeignErrorConventionKind::NonNilError; } llvm_unreachable("Unhandled ForeignErrorConvention in switch."); } /// Translate from the AST VarDeclSpecifier enum to the /// Serialization enum values, which are guaranteed to be stable. static uint8_t getRawStableParamDeclSpecifier(swift::ParamDecl::Specifier sf) { switch (sf) { case swift::ParamDecl::Specifier::Default: return uint8_t(serialization::ParamDeclSpecifier::Default); case swift::ParamDecl::Specifier::InOut: return uint8_t(serialization::ParamDeclSpecifier::InOut); case swift::ParamDecl::Specifier::Shared: return uint8_t(serialization::ParamDeclSpecifier::Shared); case swift::ParamDecl::Specifier::Owned: return uint8_t(serialization::ParamDeclSpecifier::Owned); } llvm_unreachable("bad param decl specifier kind"); } static uint8_t getRawStableVarDeclIntroducer(swift::VarDecl::Introducer intr) { switch (intr) { case swift::VarDecl::Introducer::Let: return uint8_t(serialization::VarDeclIntroducer::Let); case swift::VarDecl::Introducer::Var: return uint8_t(serialization::VarDeclIntroducer::Var); } llvm_unreachable("bad variable decl introducer kind"); } /// Translate from the AST derivative function kind enum to the Serialization /// enum values, which are guaranteed to be stable. static uint8_t getRawStableAutoDiffDerivativeFunctionKind( swift::AutoDiffDerivativeFunctionKind kind) { switch (kind) { SIMPLE_CASE(AutoDiffDerivativeFunctionKind, JVP) SIMPLE_CASE(AutoDiffDerivativeFunctionKind, VJP) } llvm_unreachable("bad derivative function kind"); } /// Translate from the AST differentiability kind enum to the Serialization enum /// values, which are guaranteed to be stable. static uint8_t getRawStableDifferentiabilityKind( swift::DifferentiabilityKind diffKind) { switch (diffKind) { SIMPLE_CASE(DifferentiabilityKind, NonDifferentiable) SIMPLE_CASE(DifferentiabilityKind, Forward) SIMPLE_CASE(DifferentiabilityKind, Reverse) SIMPLE_CASE(DifferentiabilityKind, Normal) SIMPLE_CASE(DifferentiabilityKind, Linear) } llvm_unreachable("bad differentiability kind"); } #undef SIMPLE_CASE /// Returns true if the declaration of \p decl depends on \p problemContext /// based on lexical nesting. /// /// - \p decl is \p problemContext /// - \p decl is declared within \p problemContext /// - \p decl is declared in an extension of a type that depends on /// \p problemContext static bool contextDependsOn(const NominalTypeDecl *decl, const DeclContext *problemContext) { SmallPtrSet seenExtensionDCs; const DeclContext *dc = decl; do { if (dc == problemContext) return true; if (auto *extension = dyn_cast(dc)) { if (extension->isChildContextOf(problemContext)) return true; // Avoid cycles when Left.Nested depends on Right.Nested somehow. bool isNewlySeen = seenExtensionDCs.insert(extension).second; if (!isNewlySeen) break; dc = extension->getSelfNominalTypeDecl(); } else { dc = dc->getParent(); } } while (dc); return false; } static void collectDependenciesFromType(llvm::SmallSetVector &seen, Type ty, const DeclContext *excluding) { if (!ty) return; ty.visit([&](Type next) { auto *nominal = next->getAnyNominal(); if (!nominal) return; if (contextDependsOn(nominal, excluding)) return; seen.insert(nominal->getDeclaredInterfaceType()); }); } static void collectDependenciesFromRequirement(llvm::SmallSetVector &seen, const Requirement &req, const DeclContext *excluding) { collectDependenciesFromType(seen, req.getFirstType(), excluding); if (req.getKind() != RequirementKind::Layout) collectDependenciesFromType(seen, req.getSecondType(), excluding); } static SmallVector collectDependenciesFromType(Type ty) { llvm::SmallSetVector result; collectDependenciesFromType(result, ty, /*excluding*/nullptr); return result.takeVector(); } class Serializer::DeclSerializer : public DeclVisitor { Serializer &S; DeclID id; SmallVectorImpl &exportedPrespecializationDecls; bool didVerifyAttrs = false; template void verifyAttrSerializable(const DeclKind *D) { ::verifyAttrSerializable(D); didVerifyAttrs = true; } void writeDeclAttribute(const Decl *D, const DeclAttribute *DA) { using namespace decls_block; // Completely ignore attributes that aren't serialized. if (DA->isNotSerialized()) return; // Ignore attributes that have been marked invalid. (This usually means // type-checking removed them, but only provided a warning rather than an // error.) if (DA->isInvalid()) return; switch (DA->getKind()) { case DAK_RawDocComment: case DAK_ReferenceOwnership: // Serialized as part of the type. case DAK_AccessControl: case DAK_SetterAccess: case DAK_ObjCBridged: case DAK_SynthesizedProtocol: case DAK_Implements: case DAK_ObjCRuntimeName: case DAK_RestatedObjCConformance: case DAK_ClangImporterSynthesizedType: case DAK_PrivateImport: llvm_unreachable("cannot serialize attribute"); case DAK_Count: llvm_unreachable("not a real attribute"); #define SIMPLE_DECL_ATTR(_, CLASS, ...)\ case DAK_##CLASS: { \ auto abbrCode = S.DeclTypeAbbrCodes[CLASS##DeclAttrLayout::Code]; \ CLASS##DeclAttrLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode, \ DA->isImplicit()); \ return; \ } #include "swift/AST/Attr.def" case DAK_SILGenName: { auto *theAttr = cast(DA); auto abbrCode = S.DeclTypeAbbrCodes[SILGenNameDeclAttrLayout::Code]; SILGenNameDeclAttrLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode, theAttr->isImplicit(), theAttr->Name); return; } case DAK_CDecl: { auto *theAttr = cast(DA); auto abbrCode = S.DeclTypeAbbrCodes[CDeclDeclAttrLayout::Code]; CDeclDeclAttrLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode, theAttr->isImplicit(), theAttr->Name); return; } case DAK_SPIAccessControl: { auto theAttr = cast(DA); auto abbrCode = S.DeclTypeAbbrCodes[SPIAccessControlDeclAttrLayout::Code]; SmallVector spis; for (auto spi : theAttr->getSPIGroups()) { assert(!spi.empty() && "Empty SPI name"); spis.push_back(S.addDeclBaseNameRef(spi)); } SPIAccessControlDeclAttrLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode, spis); return; } case DAK_Alignment: { auto *theAlignment = cast(DA); auto abbrCode = S.DeclTypeAbbrCodes[AlignmentDeclAttrLayout::Code]; AlignmentDeclAttrLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode, theAlignment->isImplicit(), theAlignment->getValue()); return; } case DAK_SwiftNativeObjCRuntimeBase: { auto *theBase = cast(DA); auto abbrCode = S.DeclTypeAbbrCodes[SwiftNativeObjCRuntimeBaseDeclAttrLayout::Code]; auto nameID = S.addDeclBaseNameRef(theBase->BaseClassName); SwiftNativeObjCRuntimeBaseDeclAttrLayout::emitRecord( S.Out, S.ScratchRecord, abbrCode, theBase->isImplicit(), nameID); return; } case DAK_Semantics: { auto *theAttr = cast(DA); auto abbrCode = S.DeclTypeAbbrCodes[SemanticsDeclAttrLayout::Code]; SemanticsDeclAttrLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode, theAttr->isImplicit(), theAttr->Value); return; } case DAK_Inline: { auto *theAttr = cast(DA); auto abbrCode = S.DeclTypeAbbrCodes[InlineDeclAttrLayout::Code]; InlineDeclAttrLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode, (unsigned)theAttr->getKind()); return; } case DAK_ActorIndependent: { auto *theAttr = cast(DA); auto abbrCode = S.DeclTypeAbbrCodes[ActorIndependentDeclAttrLayout::Code]; ActorIndependentDeclAttrLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode, (unsigned)theAttr->getKind()); return; } case DAK_Optimize: { auto *theAttr = cast(DA); auto abbrCode = S.DeclTypeAbbrCodes[OptimizeDeclAttrLayout::Code]; OptimizeDeclAttrLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode, (unsigned)theAttr->getMode()); return; } case DAK_Effects: { auto *theAttr = cast(DA); auto abbrCode = S.DeclTypeAbbrCodes[EffectsDeclAttrLayout::Code]; EffectsDeclAttrLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode, (unsigned)theAttr->getKind()); return; } case DAK_OriginallyDefinedIn: { auto *theAttr = cast(DA); ENCODE_VER_TUPLE(Moved, llvm::Optional(theAttr->MovedVersion)); auto abbrCode = S.DeclTypeAbbrCodes[OriginallyDefinedInDeclAttrLayout::Code]; llvm::SmallString<32> blob; blob.append(theAttr->OriginalModuleName.str()); blob.push_back('\0'); OriginallyDefinedInDeclAttrLayout::emitRecord( S.Out, S.ScratchRecord, abbrCode, theAttr->isImplicit(), LIST_VER_TUPLE_PIECES(Moved), static_cast(theAttr->Platform), blob); return; } case DAK_Available: { auto *theAttr = cast(DA); ENCODE_VER_TUPLE(Introduced, theAttr->Introduced) ENCODE_VER_TUPLE(Deprecated, theAttr->Deprecated) ENCODE_VER_TUPLE(Obsoleted, theAttr->Obsoleted) llvm::SmallString<32> blob; blob.append(theAttr->Message); blob.append(theAttr->Rename); auto abbrCode = S.DeclTypeAbbrCodes[AvailableDeclAttrLayout::Code]; AvailableDeclAttrLayout::emitRecord( S.Out, S.ScratchRecord, abbrCode, theAttr->isImplicit(), theAttr->isUnconditionallyUnavailable(), theAttr->isUnconditionallyDeprecated(), theAttr->isPackageDescriptionVersionSpecific(), LIST_VER_TUPLE_PIECES(Introduced), LIST_VER_TUPLE_PIECES(Deprecated), LIST_VER_TUPLE_PIECES(Obsoleted), static_cast(theAttr->Platform), theAttr->Message.size(), theAttr->Rename.size(), blob); return; } case DAK_ObjC: { auto *theAttr = cast(DA); SmallVector pieces; unsigned numArgs = 0; if (auto name = theAttr->getName()) { numArgs = name->getNumArgs() + 1; for (auto piece : name->getSelectorPieces()) { pieces.push_back(S.addDeclBaseNameRef(piece)); } } auto abbrCode = S.DeclTypeAbbrCodes[ObjCDeclAttrLayout::Code]; ObjCDeclAttrLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode, theAttr->isImplicit(), theAttr->isSwift3Inferred(), theAttr->isNameImplicit(), numArgs, pieces); return; } case DAK_Specialize: { auto abbrCode = S.DeclTypeAbbrCodes[SpecializeDeclAttrLayout::Code]; auto attr = cast(DA); auto targetFun = attr->getTargetFunctionName(); auto *targetFunDecl = attr->getTargetFunctionDecl(cast(D)); SmallVector pieces; // encodes whether this a a simple or compound name by adding one. size_t numArgs = 0; if (targetFun) { pieces.push_back(S.addDeclBaseNameRef(targetFun.getBaseName())); for (auto argName : targetFun.getArgumentNames()) pieces.push_back(S.addDeclBaseNameRef(argName)); if (targetFun.isSimpleName()) { assert(pieces.size() == 1); numArgs = 1; } else numArgs = pieces.size() + 1; } for (auto spi : attr->getSPIGroups()) { assert(!spi.empty() && "Empty SPI name"); pieces.push_back(S.addDeclBaseNameRef(spi)); } auto numSPIGroups = attr->getSPIGroups().size(); assert(pieces.size() == numArgs + numSPIGroups || pieces.size() == (numArgs - 1 + numSPIGroups)); SpecializeDeclAttrLayout::emitRecord( S.Out, S.ScratchRecord, abbrCode, (unsigned)attr->isExported(), (unsigned)attr->getSpecializationKind(), S.addGenericSignatureRef(attr->getSpecializedSignature()), S.addDeclRef(targetFunDecl), numArgs, numSPIGroups, pieces); return; } case DAK_DynamicReplacement: { auto abbrCode = S.DeclTypeAbbrCodes[DynamicReplacementDeclAttrLayout::Code]; auto theAttr = cast(DA); auto replacedFun = theAttr->getReplacedFunctionName(); SmallVector pieces; pieces.push_back(S.addDeclBaseNameRef(replacedFun.getBaseName())); for (auto argName : replacedFun.getArgumentNames()) pieces.push_back(S.addDeclBaseNameRef(argName)); auto *afd = cast(D)->getDynamicallyReplacedDecl(); assert(afd && "Missing replaced decl!"); DynamicReplacementDeclAttrLayout::emitRecord( S.Out, S.ScratchRecord, abbrCode, false, /*implicit flag*/ S.addDeclRef(afd), pieces.size(), pieces); return; } case DAK_TypeEraser: { auto abbrCode = S.DeclTypeAbbrCodes[TypeEraserDeclAttrLayout::Code]; auto attr = cast(DA); auto typeEraser = attr->getResolvedType(cast(D)); assert(typeEraser && "Failed to resolve erasure type!"); TypeEraserDeclAttrLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode, attr->isImplicit(), S.addTypeRef(typeEraser)); return; } case DAK_Custom: { auto abbrCode = S.DeclTypeAbbrCodes[CustomDeclAttrLayout::Code]; auto theAttr = cast(DA); CustomDeclAttrLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode, theAttr->isImplicit(), S.addTypeRef(theAttr->getType()), theAttr->isArgUnsafe()); return; } case DAK_ProjectedValueProperty: { auto abbrCode = S.DeclTypeAbbrCodes[ProjectedValuePropertyDeclAttrLayout::Code]; auto theAttr = cast(DA); ProjectedValuePropertyDeclAttrLayout::emitRecord( S.Out, S.ScratchRecord, abbrCode, theAttr->isImplicit(), S.addDeclBaseNameRef(theAttr->ProjectionPropertyName)); break; } case DAK_Differentiable: { auto abbrCode = S.DeclTypeAbbrCodes[DifferentiableDeclAttrLayout::Code]; auto *attr = cast(DA); assert(attr->getOriginalDeclaration() && "`@differentiable` attribute should have original declaration set " "during construction or parsing"); auto *paramIndices = attr->getParameterIndices(); assert(paramIndices && "Parameter indices must be resolved"); SmallVector paramIndicesVector; for (unsigned i : range(paramIndices->getCapacity())) paramIndicesVector.push_back(paramIndices->contains(i)); DifferentiableDeclAttrLayout::emitRecord( S.Out, S.ScratchRecord, abbrCode, attr->isImplicit(), getRawStableDifferentiabilityKind(attr->getDifferentiabilityKind()), S.addGenericSignatureRef(attr->getDerivativeGenericSignature()), paramIndicesVector); return; } case DAK_Derivative: { auto abbrCode = S.DeclTypeAbbrCodes[DerivativeDeclAttrLayout::Code]; auto *attr = cast(DA); auto &ctx = S.getASTContext(); assert(attr->getOriginalFunction(ctx) && "`@derivative` attribute should have original declaration set " "during construction or parsing"); auto origDeclNameRef = attr->getOriginalFunctionName(); auto origName = origDeclNameRef.Name.getBaseName(); IdentifierID origNameId = S.addDeclBaseNameRef(origName); DeclID origDeclID = S.addDeclRef(attr->getOriginalFunction(ctx)); auto derivativeKind = getRawStableAutoDiffDerivativeFunctionKind(attr->getDerivativeKind()); uint8_t rawAccessorKind = 0; auto origAccessorKind = origDeclNameRef.AccessorKind; if (origAccessorKind) rawAccessorKind = uint8_t(getStableAccessorKind(*origAccessorKind)); auto *parameterIndices = attr->getParameterIndices(); assert(parameterIndices && "Parameter indices must be resolved"); SmallVector paramIndicesVector; for (unsigned i : range(parameterIndices->getCapacity())) paramIndicesVector.push_back(parameterIndices->contains(i)); DerivativeDeclAttrLayout::emitRecord( S.Out, S.ScratchRecord, abbrCode, attr->isImplicit(), origNameId, origAccessorKind.hasValue(), rawAccessorKind, origDeclID, derivativeKind, paramIndicesVector); return; } case DAK_Transpose: { auto abbrCode = S.DeclTypeAbbrCodes[TransposeDeclAttrLayout::Code]; auto *attr = cast(DA); assert(attr->getOriginalFunction() && "`@transpose` attribute should have original declaration set " "during construction or parsing"); auto origName = attr->getOriginalFunctionName().Name.getBaseName(); IdentifierID origNameId = S.addDeclBaseNameRef(origName); DeclID origDeclID = S.addDeclRef(attr->getOriginalFunction()); auto *parameterIndices = attr->getParameterIndices(); assert(parameterIndices && "Parameter indices must be resolved"); SmallVector paramIndicesVector; for (unsigned i : range(parameterIndices->getCapacity())) paramIndicesVector.push_back(parameterIndices->contains(i)); TransposeDeclAttrLayout::emitRecord( S.Out, S.ScratchRecord, abbrCode, attr->isImplicit(), origNameId, origDeclID, paramIndicesVector); return; } case DAK_CompletionHandlerAsync: { auto *attr = cast(DA); auto abbrCode = S.DeclTypeAbbrCodes[CompletionHandlerAsyncDeclAttrLayout::Code]; assert(attr->AsyncFunctionDecl && "Serializing unresolved completion handler async function decl"); auto asyncFuncDeclID = S.addDeclRef(attr->AsyncFunctionDecl); CompletionHandlerAsyncDeclAttrLayout::emitRecord( S.Out, S.ScratchRecord, abbrCode, attr->isImplicit(), attr->CompletionHandlerIndex, asyncFuncDeclID); return; } } } void writeDiscriminatorsIfNeeded(const ValueDecl *value) { using namespace decls_block; auto *storage = dyn_cast(value); auto access = value->getFormalAccess(); // Emit the private discriminator for private decls. // FIXME: We shouldn't need to encode this for /all/ private decls. // In theory we can follow the same rules as mangling and only include // the outermost private context. bool shouldEmitPrivateDiscriminator = access <= swift::AccessLevel::FilePrivate && !value->getDeclContext()->isLocalContext(); // Emit the the filename for private mapping for private decls and // decls with private accessors if compiled with -enable-private-imports. bool shouldEmitFilenameForPrivate = S.M->arePrivateImportsEnabled() && !value->getDeclContext()->isLocalContext() && (access <= swift::AccessLevel::FilePrivate || (storage && storage->getFormalAccess() >= swift::AccessLevel::Internal && storage->hasPrivateAccessor())); if (shouldEmitFilenameForPrivate || shouldEmitPrivateDiscriminator) { auto topLevelSubcontext = value->getDeclContext()->getModuleScopeContext(); if (auto *enclosingFile = dyn_cast(topLevelSubcontext)) { if (shouldEmitPrivateDiscriminator) { Identifier discriminator = enclosingFile->getDiscriminatorForPrivateValue(value); unsigned abbrCode = S.DeclTypeAbbrCodes[PrivateDiscriminatorLayout::Code]; PrivateDiscriminatorLayout::emitRecord( S.Out, S.ScratchRecord, abbrCode, S.addDeclBaseNameRef(discriminator)); } auto getFilename = [](FileUnit *enclosingFile, const ValueDecl *decl) -> StringRef { if (auto *SF = dyn_cast(enclosingFile)) { return llvm::sys::path::filename(SF->getFilename()); } else if (auto *LF = dyn_cast(enclosingFile)) { return LF->getFilenameForPrivateDecl(decl); } return StringRef(); }; if (shouldEmitFilenameForPrivate) { auto filename = getFilename(enclosingFile, value); if (!filename.empty()) { auto filenameID = S.addFilename(filename); FilenameForPrivateLayout::emitRecord( S.Out, S.ScratchRecord, S.DeclTypeAbbrCodes[FilenameForPrivateLayout::Code], filenameID); } } } } if (value->getDeclContext()->isLocalContext()) { auto discriminator = value->getLocalDiscriminator(); auto abbrCode = S.DeclTypeAbbrCodes[LocalDiscriminatorLayout::Code]; LocalDiscriminatorLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode, discriminator); } } void writeForeignErrorConvention(const ForeignErrorConvention &fec) { using namespace decls_block; auto kind = getRawStableForeignErrorConventionKind(fec.getKind()); uint8_t isOwned = fec.isErrorOwned() == ForeignErrorConvention::IsOwned; uint8_t isReplaced = bool(fec.isErrorParameterReplacedWithVoid()); TypeID errorParameterTypeID = S.addTypeRef(fec.getErrorParameterType()); TypeID resultTypeID; switch (fec.getKind()) { case ForeignErrorConvention::ZeroResult: case ForeignErrorConvention::NonZeroResult: resultTypeID = S.addTypeRef(fec.getResultType()); break; case ForeignErrorConvention::ZeroPreservedResult: case ForeignErrorConvention::NilResult: case ForeignErrorConvention::NonNilError: resultTypeID = 0; break; } auto abbrCode = S.DeclTypeAbbrCodes[ForeignErrorConventionLayout::Code]; ForeignErrorConventionLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode, static_cast(kind), isOwned, isReplaced, fec.getErrorParameterIndex(), errorParameterTypeID, resultTypeID); } void writeForeignAsyncConvention(const ForeignAsyncConvention &fac) { using namespace decls_block; TypeID completionHandlerTypeID = S.addTypeRef(fac.completionHandlerType()); unsigned rawErrorParameterIndex = fac.completionHandlerErrorParamIndex() .map([](unsigned index) { return index + 1; }).getValueOr(0); unsigned rawErrorFlagParameterIndex = fac.completionHandlerFlagParamIndex() .map([](unsigned index) { return index + 1; }).getValueOr(0); auto abbrCode = S.DeclTypeAbbrCodes[ForeignAsyncConventionLayout::Code]; ForeignAsyncConventionLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode, completionHandlerTypeID, fac.completionHandlerParamIndex(), rawErrorParameterIndex, rawErrorFlagParameterIndex, fac.completionHandlerFlagIsErrorOnZero()); } void writeGenericParams(const GenericParamList *genericParams) { using namespace decls_block; // Don't write anything if there are no generic params. if (!genericParams) return; SmallVector paramIDs; for (auto next : genericParams->getParams()) paramIDs.push_back(S.addDeclRef(next)); unsigned abbrCode = S.DeclTypeAbbrCodes[GenericParamListLayout::Code]; GenericParamListLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode, paramIDs); } void writeParameterList(const ParameterList *PL) { using namespace decls_block; SmallVector paramIDs; for (const ParamDecl *param : *PL) paramIDs.push_back(S.addDeclRef(param)); unsigned abbrCode = S.DeclTypeAbbrCodes[ParameterListLayout::Code]; ParameterListLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode, paramIDs); } /// Writes an array of members for a decl context. /// /// \param parentID The DeclID of the context. /// \param members The decls within the context. /// \param isClass True if the context could be a class context (class, /// class extension, or protocol). void writeMembers(DeclID parentID, ArrayRef members, bool isClass) { using namespace decls_block; SmallVector memberIDs; for (auto member : members) { if (!shouldSerializeMember(member)) continue; DeclID memberID = S.addDeclRef(member); memberIDs.push_back(memberID); if (auto VD = dyn_cast(member)) { // Record parent->members in subtable of DeclMemberNames if (VD->hasName() && !VD->getBaseName().empty()) { std::unique_ptr &memberTable = S.DeclMemberNames[VD->getBaseName()].second; if (!memberTable) { memberTable = std::make_unique(); } (*memberTable)[parentID].push_back(memberID); } // Same as above, but for @_implements attributes if (auto A = VD->getAttrs().getAttribute()) { std::unique_ptr &memberTable = S.DeclMemberNames[A->getMemberName().getBaseName()].second; if (!memberTable) { memberTable = std::make_unique(); } (*memberTable)[parentID].push_back(memberID); } // Possibly add a record to ClassMembersForDynamicLookup too. if (isClass) { if (VD->canBeAccessedByDynamicLookup()) { auto &list = S.ClassMembersForDynamicLookup[VD->getBaseName()]; list.push_back({getKindForTable(VD), memberID}); } } } } unsigned abbrCode = S.DeclTypeAbbrCodes[MembersLayout::Code]; MembersLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode, memberIDs); } /// Writes the given pattern, recursively. void writePattern(const Pattern *pattern) { using namespace decls_block; // Retrieve the type of the pattern. auto getPatternType = [&] { if (!pattern->hasType()) { if (S.allowCompilerErrors()) return ErrorType::get(S.getASTContext()); llvm_unreachable("all nodes should have types"); } Type type = pattern->getType(); // If we have a contextual type, map out to an interface type. if (type->hasArchetype()) type = type->mapTypeOutOfContext(); return type; }; assert(pattern && "null pattern"); switch (pattern->getKind()) { case PatternKind::Paren: { unsigned abbrCode = S.DeclTypeAbbrCodes[ParenPatternLayout::Code]; ParenPatternLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode); writePattern(cast(pattern)->getSubPattern()); break; } case PatternKind::Tuple: { auto tuple = cast(pattern); unsigned abbrCode = S.DeclTypeAbbrCodes[TuplePatternLayout::Code]; TuplePatternLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode, S.addTypeRef(getPatternType()), tuple->getNumElements()); abbrCode = S.DeclTypeAbbrCodes[TuplePatternEltLayout::Code]; for (auto &elt : tuple->getElements()) { // FIXME: Default argument expressions? TuplePatternEltLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode, S.addDeclBaseNameRef(elt.getLabel())); writePattern(elt.getPattern()); } break; } case PatternKind::Named: { auto named = cast(pattern); unsigned abbrCode = S.DeclTypeAbbrCodes[NamedPatternLayout::Code]; NamedPatternLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode, S.addDeclRef(named->getDecl()), S.addTypeRef(getPatternType())); break; } case PatternKind::Any: { unsigned abbrCode = S.DeclTypeAbbrCodes[AnyPatternLayout::Code]; AnyPatternLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode, S.addTypeRef(getPatternType())); break; } case PatternKind::Typed: { auto typed = cast(pattern); unsigned abbrCode = S.DeclTypeAbbrCodes[TypedPatternLayout::Code]; TypedPatternLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode, S.addTypeRef(getPatternType())); writePattern(typed->getSubPattern()); break; } case PatternKind::Is: case PatternKind::EnumElement: case PatternKind::OptionalSome: case PatternKind::Bool: case PatternKind::Expr: llvm_unreachable("Refutable patterns cannot be serialized"); case PatternKind::Binding: { auto var = cast(pattern); unsigned abbrCode = S.DeclTypeAbbrCodes[BindingPatternLayout::Code]; BindingPatternLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode, var->isLet()); writePattern(var->getSubPattern()); break; } } } void writeDefaultWitnessTable(const ProtocolDecl *proto) { using namespace decls_block; SmallVector witnessIDs; for (auto member : proto->getAllMembers()) { if (auto *value = dyn_cast(member)) { auto witness = proto->getDefaultWitness(value); if (!witness) continue; DeclID requirementID = S.addDeclRef(value); DeclID witnessID = S.addDeclRef(witness.getDecl()); witnessIDs.push_back(requirementID); witnessIDs.push_back(witnessID); // FIXME: Substitutions } } unsigned abbrCode = S.DeclTypeAbbrCodes[DefaultWitnessTableLayout::Code]; DefaultWitnessTableLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode, witnessIDs); } /// Writes the body text of the provided funciton, if the function is /// inlinable and has body text. void writeInlinableBodyTextIfNeeded(const AbstractFunctionDecl *AFD) { using namespace decls_block; // Only serialize the text for an inlinable function body if we're emitting // a partial module. It's not needed in the final module file, but it's // needed in partial modules so you can emit a module interface after // merging them. if (!S.SF) return; if (AFD->getResilienceExpansion() != swift::ResilienceExpansion::Minimal) return; if (!AFD->hasInlinableBodyText()) return; SmallString<128> scratch; auto body = AFD->getInlinableBodyText(scratch); unsigned abbrCode = S.DeclTypeAbbrCodes[InlinableBodyTextLayout::Code]; InlinableBodyTextLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode, body); } unsigned getNumberOfRequiredVTableEntries( const AbstractStorageDecl *storage) const { unsigned count = 0; for (auto *accessor : storage->getAllAccessors()) { if (accessor->needsNewVTableEntry()) count++; } return count; } /// Returns true if a client can still use decls that override \p overridden /// even if \p overridden itself isn't available (isn't found, can't be /// imported, can't be deserialized, whatever). /// /// This should be kept conservative. Compiler crashes are still better than /// miscompiles. static bool overriddenDeclAffectsABI(const ValueDecl *overridden) { if (!overridden) return false; // There's one case where we know a declaration doesn't affect the ABI of // its overrides after they've been compiled: if the declaration is '@objc' // and 'dynamic'. In that case, all accesses to the method or property will // go through the Objective-C method tables anyway. if (overridden->hasClangNode() || overridden->shouldUseObjCDispatch()) return false; return true; } public: DeclSerializer(Serializer &S, DeclID id, SmallVectorImpl &exportedPrespecializationDecls) : S(S), id(id), exportedPrespecializationDecls(exportedPrespecializationDecls) {} ~DeclSerializer() { assert(didVerifyAttrs); } void visit(const Decl *D) { if (D->isInvalid()) writeDeclErrorFlag(); // Emit attributes (if any). for (auto Attr : D->getAttrs()) writeDeclAttribute(D, Attr); if (auto *value = dyn_cast(D)) writeDiscriminatorsIfNeeded(value); if (auto *afd = dyn_cast(D)) { noteUseOfExportedPrespecialization(afd); } DeclVisitor::visit(const_cast(D)); } void writeDeclErrorFlag() { using namespace decls_block; unsigned abbrCode = S.DeclTypeAbbrCodes[ErrorFlagLayout::Code]; ErrorFlagLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode); } void noteUseOfExportedPrespecialization(const AbstractFunctionDecl *afd) { for (auto *A : afd->getAttrs().getAttributes()) { auto *SA = cast(A); if (!SA->isExported()) continue; if (auto *targetFunctionDecl = SA->getTargetFunctionDecl(afd)) { exportedPrespecializationDecls.push_back(S.addDeclRef(afd)); } } } /// If this gets referenced, we forgot to handle a decl. void visitDecl(const Decl *) = delete; void visitExtensionDecl(const ExtensionDecl *extension) { using namespace decls_block; verifyAttrSerializable(extension); auto contextID = S.addDeclContextRef(extension->getDeclContext()); Type extendedType = extension->getExtendedType(); assert(!extendedType->hasArchetype()); // FIXME: Use the canonical type here in order to minimize circularity // issues at deserialization time. A known problematic case here is // "extension of typealias Foo"; "typealias Foo = SomeKit.Bar"; and then // trying to import Bar accidentally asking for all of its extensions // (perhaps because we're searching for a conformance). // // We could limit this to only the problematic cases, but it seems like a // simpler user model to just always desugar extension types. extendedType = extendedType->getCanonicalType(); auto conformances = extension->getLocalConformances( ConformanceLookupKind::All); SmallVector inheritedAndDependencyTypes; for (auto inherited : extension->getInherited()) { assert(!inherited.getType() || !inherited.getType()->hasArchetype()); inheritedAndDependencyTypes.push_back(S.addTypeRef(inherited.getType())); } size_t numInherited = inheritedAndDependencyTypes.size(); llvm::SmallSetVector dependencies; collectDependenciesFromType( dependencies, extendedType, /*excluding*/nullptr); for (Requirement req : extension->getGenericRequirements()) { collectDependenciesFromRequirement(dependencies, req, /*excluding*/nullptr); } for (auto dependencyTy : dependencies) inheritedAndDependencyTypes.push_back(S.addTypeRef(dependencyTy)); unsigned abbrCode = S.DeclTypeAbbrCodes[ExtensionLayout::Code]; auto extendedNominal = extension->getExtendedNominal(); ExtensionLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode, S.addTypeRef(extendedType), S.addDeclRef(extendedNominal), contextID.getOpaqueValue(), extension->isImplicit(), S.addGenericSignatureRef( extension->getGenericSignature()), conformances.size(), numInherited, inheritedAndDependencyTypes); bool isClassExtension = false; if (extendedNominal) { isClassExtension = isa(extendedNominal) || isa(extendedNominal); } // Extensions of nested generic types have multiple generic parameter // lists. Collect them all, from the innermost to outermost. SmallVector allGenericParams; for (auto *genericParams = extension->getGenericParams(); genericParams != nullptr; genericParams = genericParams->getOuterParameters()) { allGenericParams.push_back(genericParams); } // Reverse the list, and write the parameter lists, from outermost // to innermost. for (auto *genericParams : llvm::reverse(allGenericParams)) writeGenericParams(genericParams); writeMembers(id, extension->getAllMembers(), isClassExtension); S.writeConformances(conformances, S.DeclTypeAbbrCodes); } void visitPatternBindingDecl(const PatternBindingDecl *binding) { using namespace decls_block; verifyAttrSerializable(binding); auto contextID = S.addDeclContextRef(binding->getDeclContext()); SmallVector initContextIDs; for (unsigned i : range(binding->getNumPatternEntries())) { auto initContextID = S.addDeclContextRef(binding->getInitContext(i)); if (!initContextIDs.empty()) { initContextIDs.push_back(initContextID.getOpaqueValue()); } else if (initContextID) { initContextIDs.append(i, 0); initContextIDs.push_back(initContextID.getOpaqueValue()); } } unsigned abbrCode = S.DeclTypeAbbrCodes[PatternBindingLayout::Code]; PatternBindingLayout::emitRecord( S.Out, S.ScratchRecord, abbrCode, contextID.getOpaqueValue(), binding->isImplicit(), binding->isStatic(), uint8_t(getStableStaticSpelling(binding->getStaticSpelling())), binding->getNumPatternEntries(), initContextIDs); DeclContext *owningDC = nullptr; if (binding->getDeclContext()->isTypeContext()) owningDC = binding->getDeclContext(); for (auto entryIdx : range(binding->getNumPatternEntries())) { writePattern(binding->getPattern(entryIdx)); // Ignore initializer; external clients don't need to know about it. } } void visitPrecedenceGroupDecl(const PrecedenceGroupDecl *group) { using namespace decls_block; verifyAttrSerializable(group); auto contextID = S.addDeclContextRef(group->getDeclContext()); auto nameID = S.addDeclBaseNameRef(group->getName()); auto associativity = getRawStableAssociativity(group->getAssociativity()); SmallVector relations; for (auto &rel : group->getHigherThan()) { assert(rel.Group && "Undiagnosed invalid precedence group!"); relations.push_back(S.addDeclRef(rel.Group)); } for (auto &rel : group->getLowerThan()) { assert(rel.Group && "Undiagnosed invalid precedence group!"); relations.push_back(S.addDeclRef(rel.Group)); } unsigned abbrCode = S.DeclTypeAbbrCodes[PrecedenceGroupLayout::Code]; PrecedenceGroupLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode, nameID, contextID.getOpaqueValue(), associativity, group->isAssignment(), group->getHigherThan().size(), relations); } void visitInfixOperatorDecl(const InfixOperatorDecl *op) { using namespace decls_block; verifyAttrSerializable(op); auto contextID = S.addDeclContextRef(op->getDeclContext()); auto nameID = S.addDeclBaseNameRef(op->getName()); auto groupID = S.addDeclRef(op->getPrecedenceGroup()); SmallVector designatedNominalTypeDeclIDs; for (auto *decl : op->getDesignatedNominalTypes()) designatedNominalTypeDeclIDs.push_back(S.addDeclRef(decl)); unsigned abbrCode = S.DeclTypeAbbrCodes[InfixOperatorLayout::Code]; InfixOperatorLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode, nameID, contextID.getOpaqueValue(), groupID, designatedNominalTypeDeclIDs); } template void visitUnaryOperatorDecl(const OperatorDecl *op) { auto contextID = S.addDeclContextRef(op->getDeclContext()); SmallVector designatedNominalTypeDeclIDs; for (auto *decl : op->getDesignatedNominalTypes()) designatedNominalTypeDeclIDs.push_back(S.addDeclRef(decl)); unsigned abbrCode = S.DeclTypeAbbrCodes[Layout::Code]; Layout::emitRecord(S.Out, S.ScratchRecord, abbrCode, S.addDeclBaseNameRef(op->getName()), contextID.getOpaqueValue(), designatedNominalTypeDeclIDs); } void visitPrefixOperatorDecl(const PrefixOperatorDecl *op) { using namespace decls_block; verifyAttrSerializable(op); visitUnaryOperatorDecl(op); } void visitPostfixOperatorDecl(const PostfixOperatorDecl *op) { using namespace decls_block; verifyAttrSerializable(op); visitUnaryOperatorDecl(op); } void visitTypeAliasDecl(const TypeAliasDecl *typeAlias) { using namespace decls_block; assert(!typeAlias->isObjC() && "ObjC typealias is not meaningful"); verifyAttrSerializable(typeAlias); auto contextID = S.addDeclContextRef(typeAlias->getDeclContext()); auto underlying = typeAlias->getUnderlyingType(); llvm::SmallSetVector dependencies; collectDependenciesFromType(dependencies, underlying->getCanonicalType(), /*excluding*/nullptr); for (Requirement req : typeAlias->getGenericRequirements()) { collectDependenciesFromRequirement(dependencies, req, /*excluding*/nullptr); } SmallVector dependencyIDs; for (Type dep : dependencies) dependencyIDs.push_back(S.addTypeRef(dep)); uint8_t rawAccessLevel = getRawStableAccessLevel(typeAlias->getFormalAccess()); unsigned abbrCode = S.DeclTypeAbbrCodes[TypeAliasLayout::Code]; TypeAliasLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode, S.addDeclBaseNameRef(typeAlias->getName()), contextID.getOpaqueValue(), S.addTypeRef(underlying), /*no longer used*/TypeID(), typeAlias->isImplicit(), S.addGenericSignatureRef( typeAlias->getGenericSignature()), rawAccessLevel, dependencyIDs); writeGenericParams(typeAlias->getGenericParams()); } void visitGenericTypeParamDecl(const GenericTypeParamDecl *genericParam) { using namespace decls_block; verifyAttrSerializable(genericParam); unsigned abbrCode = S.DeclTypeAbbrCodes[GenericTypeParamDeclLayout::Code]; GenericTypeParamDeclLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode, S.addDeclBaseNameRef(genericParam->getName()), genericParam->isImplicit(), genericParam->getDepth(), genericParam->getIndex()); } void visitAssociatedTypeDecl(const AssociatedTypeDecl *assocType) { using namespace decls_block; verifyAttrSerializable(assocType); auto contextID = S.addDeclContextRef(assocType->getDeclContext()); SmallVector overriddenAssocTypeIDs; for (auto overridden : assocType->getOverriddenDecls()) { overriddenAssocTypeIDs.push_back(S.addDeclRef(overridden)); } unsigned abbrCode = S.DeclTypeAbbrCodes[AssociatedTypeDeclLayout::Code]; AssociatedTypeDeclLayout::emitRecord( S.Out, S.ScratchRecord, abbrCode, S.addDeclBaseNameRef(assocType->getName()), contextID.getOpaqueValue(), S.addTypeRef(assocType->getDefaultDefinitionType()), assocType->isImplicit(), overriddenAssocTypeIDs); } void visitStructDecl(const StructDecl *theStruct) { using namespace decls_block; verifyAttrSerializable(theStruct); auto contextID = S.addDeclContextRef(theStruct->getDeclContext()); auto conformances = theStruct->getLocalConformances( ConformanceLookupKind::All); SmallVector inheritedAndDependencyTypes; for (auto inherited : theStruct->getInherited()) { assert(!inherited.getType() || !inherited.getType()->hasArchetype()); inheritedAndDependencyTypes.push_back(S.addTypeRef(inherited.getType())); } llvm::SmallSetVector dependencyTypes; for (Requirement req : theStruct->getGenericRequirements()) { collectDependenciesFromRequirement(dependencyTypes, req, /*excluding*/nullptr); } for (Type ty : dependencyTypes) inheritedAndDependencyTypes.push_back(S.addTypeRef(ty)); uint8_t rawAccessLevel = getRawStableAccessLevel(theStruct->getFormalAccess()); unsigned abbrCode = S.DeclTypeAbbrCodes[StructLayout::Code]; StructLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode, S.addDeclBaseNameRef(theStruct->getName()), contextID.getOpaqueValue(), theStruct->isImplicit(), theStruct->isObjC(), S.addGenericSignatureRef( theStruct->getGenericSignature()), rawAccessLevel, conformances.size(), theStruct->getInherited().size(), inheritedAndDependencyTypes); writeGenericParams(theStruct->getGenericParams()); writeMembers(id, theStruct->getAllMembers(), false); S.writeConformances(conformances, S.DeclTypeAbbrCodes); } void visitEnumDecl(const EnumDecl *theEnum) { using namespace decls_block; verifyAttrSerializable(theEnum); auto contextID = S.addDeclContextRef(theEnum->getDeclContext()); auto conformances = theEnum->getLocalConformances( ConformanceLookupKind::All); SmallVector inheritedAndDependencyTypes; for (auto inherited : theEnum->getInherited()) { assert(!inherited.getType() || !inherited.getType()->hasArchetype()); inheritedAndDependencyTypes.push_back(S.addTypeRef(inherited.getType())); } llvm::SmallSetVector dependencyTypes; for (const EnumElementDecl *nextElt : theEnum->getAllElements()) { if (!nextElt->hasAssociatedValues()) continue; // FIXME: Types in the same module are still important for enums. It's // possible an enum element has a payload that references a type // declaration from the same module that can't be imported (for whatever // reason). However, we need a more robust handling of deserialization // dependencies that can handle circularities. rdar://problem/32359173 collectDependenciesFromType(dependencyTypes, nextElt->getArgumentInterfaceType(), /*excluding*/theEnum->getParentModule()); } for (Requirement req : theEnum->getGenericRequirements()) { collectDependenciesFromRequirement(dependencyTypes, req, /*excluding*/nullptr); } for (Type ty : dependencyTypes) inheritedAndDependencyTypes.push_back(S.addTypeRef(ty)); uint8_t rawAccessLevel = getRawStableAccessLevel(theEnum->getFormalAccess()); unsigned abbrCode = S.DeclTypeAbbrCodes[EnumLayout::Code]; EnumLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode, S.addDeclBaseNameRef(theEnum->getName()), contextID.getOpaqueValue(), theEnum->isImplicit(), theEnum->isObjC(), S.addGenericSignatureRef( theEnum->getGenericSignature()), S.addTypeRef(theEnum->getRawType()), rawAccessLevel, conformances.size(), theEnum->getInherited().size(), inheritedAndDependencyTypes); writeGenericParams(theEnum->getGenericParams()); writeMembers(id, theEnum->getAllMembers(), false); S.writeConformances(conformances, S.DeclTypeAbbrCodes); } void visitClassDecl(const ClassDecl *theClass) { using namespace decls_block; verifyAttrSerializable(theClass); assert(!theClass->isForeign()); auto contextID = S.addDeclContextRef(theClass->getDeclContext()); auto conformances = theClass->getLocalConformances( ConformanceLookupKind::NonInherited); SmallVector inheritedAndDependencyTypes; for (auto inherited : theClass->getInherited()) { assert(!inherited.getType() || !inherited.getType()->hasArchetype()); inheritedAndDependencyTypes.push_back(S.addTypeRef(inherited.getType())); } llvm::SmallSetVector dependencyTypes; if (theClass->hasSuperclass()) { // FIXME: Nested types can still be a problem here: it's possible that (for // whatever reason) they won't be able to be deserialized, in which case // we'll be in trouble forming the actual superclass type. However, we // need a more robust handling of deserialization dependencies that can // handle circularities. rdar://problem/50835214 collectDependenciesFromType(dependencyTypes, theClass->getSuperclass(), /*excluding*/theClass); } for (Requirement req : theClass->getGenericRequirements()) { collectDependenciesFromRequirement(dependencyTypes, req, /*excluding*/nullptr); } for (Type ty : dependencyTypes) inheritedAndDependencyTypes.push_back(S.addTypeRef(ty)); uint8_t rawAccessLevel = getRawStableAccessLevel(theClass->getFormalAccess()); auto mutableClass = const_cast(theClass); unsigned abbrCode = S.DeclTypeAbbrCodes[ClassLayout::Code]; ClassLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode, S.addDeclBaseNameRef(theClass->getName()), contextID.getOpaqueValue(), theClass->isImplicit(), theClass->isObjC(), theClass->isExplicitActor(), mutableClass->inheritsSuperclassInitializers(), mutableClass->hasMissingDesignatedInitializers(), S.addGenericSignatureRef( theClass->getGenericSignature()), S.addTypeRef(theClass->getSuperclass()), rawAccessLevel, conformances.size(), theClass->getInherited().size(), inheritedAndDependencyTypes); writeGenericParams(theClass->getGenericParams()); writeMembers(id, theClass->getAllMembers(), true); S.writeConformances(conformances, S.DeclTypeAbbrCodes); } void visitProtocolDecl(const ProtocolDecl *proto) { using namespace decls_block; verifyAttrSerializable(proto); auto contextID = S.addDeclContextRef(proto->getDeclContext()); SmallVector inheritedAndDependencyTypes; llvm::SmallSetVector dependencyTypes; for (auto element : proto->getInherited()) { auto elementType = element.getType(); assert(!elementType || !elementType->hasArchetype()); inheritedAndDependencyTypes.push_back(S.addTypeRef(elementType)); if (elementType && elementType->is()) dependencyTypes.insert(elementType); } for (Requirement req : proto->getRequirementSignature()) { // Requirements can be cyclic, so for now filter out any requirements // from elsewhere in the module. This isn't perfect---something else in // the module could very well fail to compile for its own reasons---but // it's better than nothing. collectDependenciesFromRequirement(dependencyTypes, req, /*excluding*/S.M); } for (Type ty : dependencyTypes) inheritedAndDependencyTypes.push_back(S.addTypeRef(ty)); uint8_t rawAccessLevel = getRawStableAccessLevel(proto->getFormalAccess()); unsigned abbrCode = S.DeclTypeAbbrCodes[ProtocolLayout::Code]; ProtocolLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode, S.addDeclBaseNameRef(proto->getName()), contextID.getOpaqueValue(), proto->isImplicit(), const_cast(proto) ->requiresClass(), proto->isObjC(), proto->existentialTypeSupported(), rawAccessLevel, proto->getInherited().size(), inheritedAndDependencyTypes); writeGenericParams(proto->getGenericParams()); S.writeGenericRequirements( proto->getRequirementSignature(), S.DeclTypeAbbrCodes); writeMembers(id, proto->getAllMembers(), true); writeDefaultWitnessTable(proto); } void visitVarDecl(const VarDecl *var) { using namespace decls_block; verifyAttrSerializable(var); auto contextID = S.addDeclContextRef(var->getDeclContext()); Accessors accessors = getAccessors(var); uint8_t rawAccessLevel = getRawStableAccessLevel(var->getFormalAccess()); uint8_t rawSetterAccessLevel = rawAccessLevel; if (var->isSettable(nullptr)) rawSetterAccessLevel = getRawStableAccessLevel(var->getSetterFormalAccess()); unsigned numBackingProperties = 0; Type ty = var->getInterfaceType(); SmallVector arrayFields; for (auto accessor : accessors.Decls) arrayFields.push_back(S.addDeclRef(accessor)); if (auto backingInfo = var->getPropertyWrapperAuxiliaryVariables()) { if (backingInfo.backingVar) { ++numBackingProperties; arrayFields.push_back(S.addDeclRef(backingInfo.backingVar)); } if (backingInfo.projectionVar) { ++numBackingProperties; arrayFields.push_back(S.addDeclRef(backingInfo.projectionVar)); } } for (Type dependency : collectDependenciesFromType(ty->getCanonicalType())) arrayFields.push_back(S.addTypeRef(dependency)); VarDecl *lazyStorage = nullptr; if (var->getAttrs().hasAttribute()) lazyStorage = var->getLazyStorageProperty(); auto rawIntroducer = getRawStableVarDeclIntroducer(var->getIntroducer()); unsigned numVTableEntries = getNumberOfRequiredVTableEntries(var); unsigned abbrCode = S.DeclTypeAbbrCodes[VarLayout::Code]; VarLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode, S.addDeclBaseNameRef(var->getName()), contextID.getOpaqueValue(), var->isImplicit(), var->isObjC(), var->isStatic(), rawIntroducer, var->isGetterMutating(), var->isSetterMutating(), var->isLazyStorageProperty(), var->isTopLevelGlobal(), S.addDeclRef(lazyStorage), accessors.OpaqueReadOwnership, accessors.ReadImpl, accessors.WriteImpl, accessors.ReadWriteImpl, accessors.Decls.size(), S.addTypeRef(ty), var->isImplicitlyUnwrappedOptional(), S.addDeclRef(var->getOverriddenDecl()), rawAccessLevel, rawSetterAccessLevel, S.addDeclRef(var->getOpaqueResultTypeDecl()), numBackingProperties, numVTableEntries, arrayFields); } void visitParamDecl(const ParamDecl *param) { using namespace decls_block; verifyAttrSerializable(param); auto contextID = S.addDeclContextRef(param->getDeclContext()); Type interfaceType = param->getInterfaceType(); // Only save the text for normal and stored property default arguments, not // any of the special ones. StringRef defaultArgumentText; SmallString<128> scratch; swift::DefaultArgumentKind argKind = param->getDefaultArgumentKind(); if (argKind == swift::DefaultArgumentKind::Normal || argKind == swift::DefaultArgumentKind::StoredProperty) defaultArgumentText = param->getDefaultValueStringRepresentation(scratch); unsigned abbrCode = S.DeclTypeAbbrCodes[ParamLayout::Code]; ParamLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode, S.addDeclBaseNameRef(param->getArgumentName()), S.addDeclBaseNameRef(param->getName()), contextID.getOpaqueValue(), getRawStableParamDeclSpecifier(param->getSpecifier()), S.addTypeRef(interfaceType), param->isImplicitlyUnwrappedOptional(), param->isVariadic(), param->isAutoClosure(), getRawStableDefaultArgumentKind(argKind), defaultArgumentText); if (interfaceType->hasError() && !S.allowCompilerErrors()) { param->getDeclContext()->printContext(llvm::errs()); interfaceType->dump(llvm::errs()); llvm_unreachable("error in interface type of parameter"); } } void visitFuncDecl(const FuncDecl *fn) { using namespace decls_block; verifyAttrSerializable(fn); auto contextID = S.addDeclContextRef(fn->getDeclContext()); unsigned abbrCode = S.DeclTypeAbbrCodes[FuncLayout::Code]; SmallVector nameComponentsAndDependencies; nameComponentsAndDependencies.push_back( S.addDeclBaseNameRef(fn->getBaseName())); for (auto argName : fn->getName().getArgumentNames()) nameComponentsAndDependencies.push_back(S.addDeclBaseNameRef(argName)); uint8_t rawAccessLevel = getRawStableAccessLevel(fn->getFormalAccess()); Type ty = fn->getInterfaceType(); for (auto dependency : collectDependenciesFromType(ty->getCanonicalType())) nameComponentsAndDependencies.push_back(S.addTypeRef(dependency)); FuncLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode, contextID.getOpaqueValue(), fn->isImplicit(), fn->isStatic(), uint8_t( getStableStaticSpelling(fn->getStaticSpelling())), fn->isObjC(), uint8_t( getStableSelfAccessKind(fn->getSelfAccessKind())), fn->hasForcedStaticDispatch(), fn->hasAsync(), fn->hasThrows(), S.addGenericSignatureRef( fn->getGenericSignature()), S.addTypeRef(fn->getResultInterfaceType()), fn->isImplicitlyUnwrappedOptional(), S.addDeclRef(fn->getOperatorDecl()), S.addDeclRef(fn->getOverriddenDecl()), overriddenDeclAffectsABI(fn->getOverriddenDecl()), fn->getName().getArgumentNames().size() + fn->getName().isCompoundName(), rawAccessLevel, fn->needsNewVTableEntry(), S.addDeclRef(fn->getOpaqueResultTypeDecl()), fn->isUserAccessible(), nameComponentsAndDependencies); writeGenericParams(fn->getGenericParams()); // Write the body parameters. writeParameterList(fn->getParameters()); if (auto errorConvention = fn->getForeignErrorConvention()) writeForeignErrorConvention(*errorConvention); if (auto asyncConvention = fn->getForeignAsyncConvention()) writeForeignAsyncConvention(*asyncConvention); writeInlinableBodyTextIfNeeded(fn); } void visitOpaqueTypeDecl(const OpaqueTypeDecl *opaqueDecl) { using namespace decls_block; verifyAttrSerializable(opaqueDecl); auto namingDeclID = S.addDeclRef(opaqueDecl->getNamingDecl()); auto contextID = S.addDeclContextRef(opaqueDecl->getDeclContext()); auto interfaceSigID = S.addGenericSignatureRef( opaqueDecl->getOpaqueInterfaceGenericSignature()); auto interfaceTypeID = S.addTypeRef(opaqueDecl->getUnderlyingInterfaceType()); auto genericSigID = S.addGenericSignatureRef(opaqueDecl->getGenericSignature()); SubstitutionMapID underlyingTypeID = 0; if (auto underlying = opaqueDecl->getUnderlyingTypeSubstitutions()) underlyingTypeID = S.addSubstitutionMapRef(*underlying); uint8_t rawAccessLevel = getRawStableAccessLevel(opaqueDecl->getFormalAccess()); unsigned abbrCode = S.DeclTypeAbbrCodes[OpaqueTypeLayout::Code]; OpaqueTypeLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode, contextID.getOpaqueValue(), namingDeclID, interfaceSigID, interfaceTypeID, genericSigID, underlyingTypeID, rawAccessLevel); writeGenericParams(opaqueDecl->getGenericParams()); } void visitAccessorDecl(const AccessorDecl *fn) { using namespace decls_block; verifyAttrSerializable(fn); auto contextID = S.addDeclContextRef(fn->getDeclContext()); unsigned abbrCode = S.DeclTypeAbbrCodes[AccessorLayout::Code]; uint8_t rawAccessLevel = getRawStableAccessLevel(fn->getFormalAccess()); uint8_t rawAccessorKind = uint8_t(getStableAccessorKind(fn->getAccessorKind())); bool overriddenAffectsABI = overriddenDeclAffectsABI(fn->getOverriddenDecl()); Type ty = fn->getInterfaceType(); SmallVector dependencies; for (auto dependency : collectDependenciesFromType(ty->getCanonicalType())) dependencies.push_back(S.addTypeRef(dependency)); AccessorLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode, contextID.getOpaqueValue(), fn->isImplicit(), fn->isStatic(), uint8_t(getStableStaticSpelling( fn->getStaticSpelling())), fn->isObjC(), uint8_t(getStableSelfAccessKind( fn->getSelfAccessKind())), fn->hasForcedStaticDispatch(), fn->hasAsync(), fn->hasThrows(), S.addGenericSignatureRef( fn->getGenericSignature()), S.addTypeRef(fn->getResultInterfaceType()), fn->isImplicitlyUnwrappedOptional(), S.addDeclRef(fn->getOverriddenDecl()), overriddenAffectsABI, S.addDeclRef(fn->getStorage()), rawAccessorKind, rawAccessLevel, fn->needsNewVTableEntry(), fn->isTransparent(), dependencies); writeGenericParams(fn->getGenericParams()); // Write the body parameters. writeParameterList(fn->getParameters()); if (auto errorConvention = fn->getForeignErrorConvention()) writeForeignErrorConvention(*errorConvention); if (auto asyncConvention = fn->getForeignAsyncConvention()) writeForeignAsyncConvention(*asyncConvention); writeInlinableBodyTextIfNeeded(fn); } void visitEnumElementDecl(const EnumElementDecl *elem) { using namespace decls_block; verifyAttrSerializable(elem); auto contextID = S.addDeclContextRef(elem->getDeclContext()); SmallVector nameComponentsAndDependencies; auto baseName = S.addDeclBaseNameRef(elem->getBaseName()); nameComponentsAndDependencies.push_back(baseName); for (auto argName : elem->getName().getArgumentNames()) nameComponentsAndDependencies.push_back(S.addDeclBaseNameRef(argName)); Type ty = elem->getInterfaceType(); for (Type dependency : collectDependenciesFromType(ty->getCanonicalType())) nameComponentsAndDependencies.push_back(S.addTypeRef(dependency)); // We only serialize the raw values of @objc enums, because they're part // of the ABI. That isn't the case for Swift enums. auto rawValueKind = EnumElementRawValueKind::None; bool isNegative = false, isRawValueImplicit = false; StringRef RawValueText; if (elem->getParentEnum()->isObjC()) { // Currently ObjC enums always have integer raw values. rawValueKind = EnumElementRawValueKind::IntegerLiteral; auto ILE = cast(elem->getStructuralRawValueExpr()); RawValueText = ILE->getDigitsText(); isNegative = ILE->isNegative(); isRawValueImplicit = ILE->isImplicit(); } unsigned abbrCode = S.DeclTypeAbbrCodes[EnumElementLayout::Code]; EnumElementLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode, contextID.getOpaqueValue(), elem->isImplicit(), elem->hasAssociatedValues(), (unsigned)rawValueKind, isRawValueImplicit, isNegative, S.addUniquedStringRef(RawValueText), elem->getName().getArgumentNames().size()+1, nameComponentsAndDependencies); if (auto *PL = elem->getParameterList()) writeParameterList(PL); } void visitSubscriptDecl(const SubscriptDecl *subscript) { using namespace decls_block; verifyAttrSerializable(subscript); auto contextID = S.addDeclContextRef(subscript->getDeclContext()); Accessors accessors = getAccessors(subscript); SmallVector nameComponentsAndDependencies; for (auto argName : subscript->getName().getArgumentNames()) nameComponentsAndDependencies.push_back(S.addDeclBaseNameRef(argName)); for (auto accessor : accessors.Decls) nameComponentsAndDependencies.push_back(S.addDeclRef(accessor)); Type ty = subscript->getInterfaceType(); for (Type dependency : collectDependenciesFromType(ty->getCanonicalType())) nameComponentsAndDependencies.push_back(S.addTypeRef(dependency)); uint8_t rawAccessLevel = getRawStableAccessLevel(subscript->getFormalAccess()); uint8_t rawSetterAccessLevel = rawAccessLevel; if (subscript->supportsMutation()) rawSetterAccessLevel = getRawStableAccessLevel(subscript->getSetterFormalAccess()); uint8_t rawStaticSpelling = uint8_t(getStableStaticSpelling(subscript->getStaticSpelling())); unsigned numVTableEntries = getNumberOfRequiredVTableEntries(subscript); unsigned abbrCode = S.DeclTypeAbbrCodes[SubscriptLayout::Code]; SubscriptLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode, contextID.getOpaqueValue(), subscript->isImplicit(), subscript->isObjC(), subscript->isGetterMutating(), subscript->isSetterMutating(), accessors.OpaqueReadOwnership, accessors.ReadImpl, accessors.WriteImpl, accessors.ReadWriteImpl, accessors.Decls.size(), S.addGenericSignatureRef( subscript->getGenericSignature()), S.addTypeRef(subscript->getElementInterfaceType()), subscript->isImplicitlyUnwrappedOptional(), S.addDeclRef(subscript->getOverriddenDecl()), rawAccessLevel, rawSetterAccessLevel, rawStaticSpelling, subscript->getName().getArgumentNames().size(), S.addDeclRef(subscript->getOpaqueResultTypeDecl()), numVTableEntries, nameComponentsAndDependencies); writeGenericParams(subscript->getGenericParams()); writeParameterList(subscript->getIndices()); } void visitConstructorDecl(const ConstructorDecl *ctor) { using namespace decls_block; verifyAttrSerializable(ctor); auto contextID = S.addDeclContextRef(ctor->getDeclContext()); SmallVector nameComponentsAndDependencies; for (auto argName : ctor->getName().getArgumentNames()) nameComponentsAndDependencies.push_back(S.addDeclBaseNameRef(argName)); Type ty = ctor->getInterfaceType(); for (Type dependency : collectDependenciesFromType(ty->getCanonicalType())) nameComponentsAndDependencies.push_back(S.addTypeRef(dependency)); uint8_t rawAccessLevel = getRawStableAccessLevel(ctor->getFormalAccess()); bool firstTimeRequired = ctor->isRequired(); if (auto *overridden = ctor->getOverriddenDecl()) if (firstTimeRequired && overridden->isRequired()) firstTimeRequired = false; unsigned abbrCode = S.DeclTypeAbbrCodes[ConstructorLayout::Code]; ConstructorLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode, contextID.getOpaqueValue(), ctor->isFailable(), ctor->isImplicitlyUnwrappedOptional(), ctor->isImplicit(), ctor->isObjC(), ctor->hasStubImplementation(), ctor->hasAsync(), ctor->hasThrows(), getStableCtorInitializerKind( ctor->getInitKind()), S.addGenericSignatureRef( ctor->getGenericSignature()), S.addDeclRef(ctor->getOverriddenDecl()), rawAccessLevel, ctor->needsNewVTableEntry(), firstTimeRequired, ctor->getName().getArgumentNames().size(), nameComponentsAndDependencies); writeGenericParams(ctor->getGenericParams()); writeParameterList(ctor->getParameters()); if (auto errorConvention = ctor->getForeignErrorConvention()) writeForeignErrorConvention(*errorConvention); if (auto asyncConvention = ctor->getForeignAsyncConvention()) writeForeignAsyncConvention(*asyncConvention); writeInlinableBodyTextIfNeeded(ctor); } void visitDestructorDecl(const DestructorDecl *dtor) { using namespace decls_block; verifyAttrSerializable(dtor); if (S.allowCompilerErrors() && dtor->isInvalid()) return; auto contextID = S.addDeclContextRef(dtor->getDeclContext()); unsigned abbrCode = S.DeclTypeAbbrCodes[DestructorLayout::Code]; DestructorLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode, contextID.getOpaqueValue(), dtor->isImplicit(), dtor->isObjC(), S.addGenericSignatureRef( dtor->getGenericSignature())); writeInlinableBodyTextIfNeeded(dtor); } void visitTopLevelCodeDecl(const TopLevelCodeDecl *) { // Top-level code is ignored; external clients don't need to know about it. } void visitImportDecl(const ImportDecl *) { llvm_unreachable("import decls should not be serialized"); } void visitIfConfigDecl(const IfConfigDecl *) { llvm_unreachable("#if block declarations should not be serialized"); } void visitPoundDiagnosticDecl(const PoundDiagnosticDecl *) { llvm_unreachable("#warning/#error declarations should not be serialized"); } void visitEnumCaseDecl(const EnumCaseDecl *) { llvm_unreachable("enum case decls should not be serialized"); } void visitModuleDecl(const ModuleDecl *) { llvm_unreachable("module decls are not serialized"); } void visitMissingMemberDecl(const MissingMemberDecl *) { llvm_unreachable("member placeholders shouldn't be serialized"); } }; void Serializer::writeASTBlockEntity(const Decl *D) { using namespace decls_block; PrettyStackTraceDecl trace("serializing", D); assert(DeclsToSerialize.hasRef(D)); BitOffset initialOffset = Out.GetCurrentBitNo(); SWIFT_DEFER { // This is important enough to leave on in Release builds. if (initialOffset == Out.GetCurrentBitNo()) { llvm::PrettyStackTraceString message("failed to serialize anything"); abort(); } }; assert((allowCompilerErrors() || !D->isInvalid()) && "cannot create a module with an invalid decl"); if (isDeclXRef(D)) { writeCrossReference(D); return; } assert(!D->hasClangNode() && "imported decls should use cross-references"); DeclSerializer(*this, DeclsToSerialize.addRef(D), exportedPrespecializationDecls) .visit(D); } #define SIMPLE_CASE(TYPENAME, VALUE) \ case swift::TYPENAME::VALUE: return uint8_t(serialization::TYPENAME::VALUE); /// Translate from the AST function representation enum to the Serialization enum /// values, which are guaranteed to be stable. static uint8_t getRawStableFunctionTypeRepresentation( swift::FunctionType::Representation cc) { switch (cc) { SIMPLE_CASE(FunctionTypeRepresentation, Swift) SIMPLE_CASE(FunctionTypeRepresentation, Block) SIMPLE_CASE(FunctionTypeRepresentation, Thin) SIMPLE_CASE(FunctionTypeRepresentation, CFunctionPointer) } llvm_unreachable("bad calling convention"); } /// Translate from the AST function representation enum to the Serialization enum /// values, which are guaranteed to be stable. static uint8_t getRawStableSILFunctionTypeRepresentation( swift::SILFunctionType::Representation cc) { switch (cc) { SIMPLE_CASE(SILFunctionTypeRepresentation, Thick) SIMPLE_CASE(SILFunctionTypeRepresentation, Block) SIMPLE_CASE(SILFunctionTypeRepresentation, Thin) SIMPLE_CASE(SILFunctionTypeRepresentation, CFunctionPointer) SIMPLE_CASE(SILFunctionTypeRepresentation, Method) SIMPLE_CASE(SILFunctionTypeRepresentation, ObjCMethod) SIMPLE_CASE(SILFunctionTypeRepresentation, WitnessMethod) SIMPLE_CASE(SILFunctionTypeRepresentation, Closure) } llvm_unreachable("bad calling convention"); } /// Translate from the AST coroutine-kind enum to the Serialization enum /// values, which are guaranteed to be stable. static uint8_t getRawStableSILCoroutineKind( swift::SILCoroutineKind kind) { switch (kind) { SIMPLE_CASE(SILCoroutineKind, None) SIMPLE_CASE(SILCoroutineKind, YieldOnce) SIMPLE_CASE(SILCoroutineKind, YieldMany) } llvm_unreachable("bad kind"); } /// Translate from the AST ownership enum to the Serialization enum /// values, which are guaranteed to be stable. static uint8_t getRawStableReferenceOwnership(swift::ReferenceOwnership ownership) { switch (ownership) { SIMPLE_CASE(ReferenceOwnership, Strong) #define REF_STORAGE(Name, ...) \ SIMPLE_CASE(ReferenceOwnership, Name) #include "swift/AST/ReferenceStorage.def" } llvm_unreachable("bad ownership kind"); } /// Translate from the AST ownership enum to the Serialization enum /// values, which are guaranteed to be stable. static uint8_t getRawStableValueOwnership(swift::ValueOwnership ownership) { switch (ownership) { SIMPLE_CASE(ValueOwnership, Default) SIMPLE_CASE(ValueOwnership, InOut) SIMPLE_CASE(ValueOwnership, Shared) SIMPLE_CASE(ValueOwnership, Owned) } llvm_unreachable("bad ownership kind"); } /// Translate from the AST ParameterConvention enum to the /// Serialization enum values, which are guaranteed to be stable. static uint8_t getRawStableParameterConvention(swift::ParameterConvention pc) { switch (pc) { SIMPLE_CASE(ParameterConvention, Indirect_In) SIMPLE_CASE(ParameterConvention, Indirect_In_Constant) SIMPLE_CASE(ParameterConvention, Indirect_In_Guaranteed) SIMPLE_CASE(ParameterConvention, Indirect_Inout) SIMPLE_CASE(ParameterConvention, Indirect_InoutAliasable) SIMPLE_CASE(ParameterConvention, Direct_Owned) SIMPLE_CASE(ParameterConvention, Direct_Unowned) SIMPLE_CASE(ParameterConvention, Direct_Guaranteed) } llvm_unreachable("bad parameter convention kind"); } /// Translate from AST SILParameterDifferentiability enum to the Serialization /// enum values, which are guaranteed to be stable. static uint8_t getRawSILParameterDifferentiability(swift::SILParameterDifferentiability pd) { switch (pd) { SIMPLE_CASE(SILParameterDifferentiability, DifferentiableOrNotApplicable) SIMPLE_CASE(SILParameterDifferentiability, NotDifferentiable) } llvm_unreachable("bad parameter differentiability kind"); } /// Translate from the AST ResultConvention enum to the /// Serialization enum values, which are guaranteed to be stable. static uint8_t getRawStableResultConvention(swift::ResultConvention rc) { switch (rc) { SIMPLE_CASE(ResultConvention, Indirect) SIMPLE_CASE(ResultConvention, Owned) SIMPLE_CASE(ResultConvention, Unowned) SIMPLE_CASE(ResultConvention, UnownedInnerPointer) SIMPLE_CASE(ResultConvention, Autoreleased) } llvm_unreachable("bad result convention kind"); } /// Translate from AST SILResultDifferentiability enum to the Serialization enum /// values, which are guaranteed to be stable. static uint8_t getRawSILResultDifferentiability(swift::SILResultDifferentiability pd) { switch (pd) { SIMPLE_CASE(SILResultDifferentiability, DifferentiableOrNotApplicable) SIMPLE_CASE(SILResultDifferentiability, NotDifferentiable) } llvm_unreachable("bad result differentiability kind"); } #undef SIMPLE_CASE /// Find the typealias given a builtin type. static TypeAliasDecl *findTypeAliasForBuiltin(ASTContext &Ctx, Type T) { /// Get the type name by chopping off "Builtin.". llvm::SmallString<32> FullName; llvm::raw_svector_ostream OS(FullName); T->print(OS); assert(FullName.startswith(BUILTIN_TYPE_NAME_PREFIX)); StringRef TypeName = FullName.substr(8); SmallVector CurModuleResults; Ctx.TheBuiltinModule->lookupValue(Ctx.getIdentifier(TypeName), NLKind::QualifiedLookup, CurModuleResults); assert(CurModuleResults.size() == 1); return cast(CurModuleResults[0]); } class Serializer::TypeSerializer : public TypeVisitor { Serializer &S; public: explicit TypeSerializer(Serializer &S) : S(S) {} /// If this gets referenced, we forgot to handle a type. void visitType(const TypeBase *) = delete; void visitErrorType(const ErrorType *ty) { if (S.allowCompilerErrors()) { using namespace decls_block; unsigned abbrCode = S.DeclTypeAbbrCodes[ErrorTypeLayout::Code]; ErrorTypeLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode, S.addTypeRef(ty->getOriginalType())); return; } llvm_unreachable("should not serialize an ErrorType"); } void visitUnresolvedType(const UnresolvedType *) { // If for some reason we have an unresolved type while compiling with // errors, just serialize an ErrorType and continue. if (S.getASTContext().LangOpts.AllowModuleWithCompilerErrors) { visitErrorType( cast(ErrorType::get(S.getASTContext()).getPointer())); return; } llvm_unreachable("should not serialize an UnresolvedType"); } void visitPlaceholderType(const PlaceholderType *) { llvm_unreachable("should not serialize a PlaceholderType"); } void visitModuleType(const ModuleType *) { llvm_unreachable("modules are currently not first-class values"); } void visitInOutType(const InOutType *) { llvm_unreachable("inout types are only used in function type parameters"); } void visitLValueType(const LValueType *) { llvm_unreachable("lvalue types are only used in function bodies"); } void visitTypeVariableType(const TypeVariableType *) { llvm_unreachable("type variables should not escape the type checker"); } void visitBuiltinTypeImpl(Type ty) { using namespace decls_block; TypeAliasDecl *typeAlias = findTypeAliasForBuiltin(S.M->getASTContext(), ty); unsigned abbrCode = S.DeclTypeAbbrCodes[BuiltinAliasTypeLayout::Code]; BuiltinAliasTypeLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode, S.addDeclRef(typeAlias, /*allowTypeAliasXRef*/true), TypeID()); } void visitBuiltinType(BuiltinType *ty) { visitBuiltinTypeImpl(ty); } void visitSILTokenType(SILTokenType *ty) { // This is serialized like a BuiltinType, even though it isn't one. visitBuiltinTypeImpl(ty); } void visitTypeAliasType(const TypeAliasType *alias) { using namespace decls_block; const TypeAliasDecl *typeAlias = alias->getDecl(); auto underlyingType = typeAlias->getUnderlyingType(); unsigned abbrCode = S.DeclTypeAbbrCodes[TypeAliasTypeLayout::Code]; TypeAliasTypeLayout::emitRecord( S.Out, S.ScratchRecord, abbrCode, S.addDeclRef(typeAlias, /*allowTypeAliasXRef*/true), S.addTypeRef(alias->getParent()), S.addTypeRef(underlyingType), S.addTypeRef(alias->getSinglyDesugaredType()), S.addSubstitutionMapRef(alias->getSubstitutionMap())); } template void serializeSimpleWrapper(Type wrappedTy) { unsigned abbrCode = S.DeclTypeAbbrCodes[Layout::Code]; Layout::emitRecord(S.Out, S.ScratchRecord, abbrCode, S.addTypeRef(wrappedTy)); } void visitParenType(const ParenType *parenTy) { using namespace decls_block; assert(parenTy->getParameterFlags().isNone()); serializeSimpleWrapper(parenTy->getUnderlyingType()); } void visitTupleType(const TupleType *tupleTy) { using namespace decls_block; unsigned abbrCode = S.DeclTypeAbbrCodes[TupleTypeLayout::Code]; TupleTypeLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode); abbrCode = S.DeclTypeAbbrCodes[TupleTypeEltLayout::Code]; for (auto &elt : tupleTy->getElements()) { assert(elt.getParameterFlags().isNone()); TupleTypeEltLayout::emitRecord( S.Out, S.ScratchRecord, abbrCode, S.addDeclBaseNameRef(elt.getName()), S.addTypeRef(elt.getType())); } } void visitNominalType(const NominalType *nominalTy) { using namespace decls_block; unsigned abbrCode = S.DeclTypeAbbrCodes[NominalTypeLayout::Code]; NominalTypeLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode, S.addDeclRef(nominalTy->getDecl()), S.addTypeRef(nominalTy->getParent())); } template void visitMetatypeImpl(const AnyMetatypeType *metatypeTy) { unsigned abbrCode = S.DeclTypeAbbrCodes[Layout::Code]; // Map the metatype representation. auto repr = getRawStableMetatypeRepresentation(metatypeTy); Layout::emitRecord(S.Out, S.ScratchRecord, abbrCode, S.addTypeRef(metatypeTy->getInstanceType()), static_cast(repr)); } void visitExistentialMetatypeType(const ExistentialMetatypeType *metatypeTy) { using namespace decls_block; visitMetatypeImpl(metatypeTy); } void visitMetatypeType(const MetatypeType *metatypeTy) { using namespace decls_block; visitMetatypeImpl(metatypeTy); } void visitDynamicSelfType(const DynamicSelfType *dynamicSelfTy) { using namespace decls_block; unsigned abbrCode = S.DeclTypeAbbrCodes[DynamicSelfTypeLayout::Code]; DynamicSelfTypeLayout::emitRecord( S.Out, S.ScratchRecord, abbrCode, S.addTypeRef(dynamicSelfTy->getSelfType())); } void visitPrimaryArchetypeType(const PrimaryArchetypeType *archetypeTy) { using namespace decls_block; auto sig = archetypeTy->getGenericEnvironment()->getGenericSignature(); GenericSignatureID sigID = S.addGenericSignatureRef(sig); auto interfaceType = archetypeTy->getInterfaceType() ->castTo(); unsigned abbrCode = S.DeclTypeAbbrCodes[PrimaryArchetypeTypeLayout::Code]; PrimaryArchetypeTypeLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode, sigID, interfaceType->getDepth(), interfaceType->getIndex()); } void visitOpenedArchetypeType(const OpenedArchetypeType *archetypeTy) { using namespace decls_block; serializeSimpleWrapper( archetypeTy->getOpenedExistentialType()); } void visitOpaqueTypeArchetypeType(const OpaqueTypeArchetypeType *archetypeTy) { using namespace decls_block; auto declID = S.addDeclRef(archetypeTy->getDecl()); auto substMapID = S.addSubstitutionMapRef(archetypeTy->getSubstitutions()); unsigned abbrCode = S.DeclTypeAbbrCodes[OpaqueArchetypeTypeLayout::Code]; OpaqueArchetypeTypeLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode, declID, substMapID); } void visitNestedArchetypeType(const NestedArchetypeType *archetypeTy) { using namespace decls_block; auto rootTypeID = S.addTypeRef(archetypeTy->getRoot()); auto interfaceTypeID = S.addTypeRef(archetypeTy->getInterfaceType()); unsigned abbrCode = S.DeclTypeAbbrCodes[NestedArchetypeTypeLayout::Code]; NestedArchetypeTypeLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode, rootTypeID, interfaceTypeID); } void visitGenericTypeParamType(const GenericTypeParamType *genericParam) { using namespace decls_block; unsigned abbrCode = S.DeclTypeAbbrCodes[GenericTypeParamTypeLayout::Code]; DeclID declIDOrDepth; unsigned indexPlusOne; if (genericParam->getDecl() && !(genericParam->getDecl()->getDeclContext()->isModuleScopeContext() && S.isDeclXRef(genericParam->getDecl()))) { declIDOrDepth = S.addDeclRef(genericParam->getDecl()); indexPlusOne = 0; } else { declIDOrDepth = genericParam->getDepth(); indexPlusOne = genericParam->getIndex() + 1; } GenericTypeParamTypeLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode, declIDOrDepth, indexPlusOne); } void visitDependentMemberType(const DependentMemberType *dependent) { using namespace decls_block; unsigned abbrCode = S.DeclTypeAbbrCodes[DependentMemberTypeLayout::Code]; assert(dependent->getAssocType() && "Unchecked dependent member type"); DependentMemberTypeLayout::emitRecord( S.Out, S.ScratchRecord, abbrCode, S.addTypeRef(dependent->getBase()), S.addDeclRef(dependent->getAssocType())); } void serializeFunctionTypeParams(const AnyFunctionType *fnTy) { using namespace decls_block; unsigned abbrCode = S.DeclTypeAbbrCodes[FunctionParamLayout::Code]; for (auto ¶m : fnTy->getParams()) { auto paramFlags = param.getParameterFlags(); auto rawOwnership = getRawStableValueOwnership(paramFlags.getValueOwnership()); FunctionParamLayout::emitRecord( S.Out, S.ScratchRecord, abbrCode, S.addDeclBaseNameRef(param.getLabel()), S.addDeclBaseNameRef(param.getInternalLabel()), S.addTypeRef(param.getPlainType()), paramFlags.isVariadic(), paramFlags.isAutoClosure(), paramFlags.isNonEphemeral(), rawOwnership, paramFlags.isNoDerivative()); } } void visitFunctionType(const FunctionType *fnTy) { using namespace decls_block; auto resultType = S.addTypeRef(fnTy->getResult()); auto clangType = S.getASTContext().LangOpts.UseClangFunctionTypes ? S.addClangTypeRef(fnTy->getClangTypeInfo().getType()) : ClangTypeID(0); auto globalActor = S.addTypeRef(fnTy->getGlobalActor()); unsigned abbrCode = S.DeclTypeAbbrCodes[FunctionTypeLayout::Code]; FunctionTypeLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode, resultType, getRawStableFunctionTypeRepresentation(fnTy->getRepresentation()), clangType, fnTy->isNoEscape(), fnTy->isSendable(), fnTy->isAsync(), fnTy->isThrowing(), getRawStableDifferentiabilityKind(fnTy->getDifferentiabilityKind()), globalActor); serializeFunctionTypeParams(fnTy); } void visitGenericFunctionType(const GenericFunctionType *fnTy) { using namespace decls_block; assert(!fnTy->isNoEscape()); auto genericSig = fnTy->getGenericSignature(); unsigned abbrCode = S.DeclTypeAbbrCodes[GenericFunctionTypeLayout::Code]; GenericFunctionTypeLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode, S.addTypeRef(fnTy->getResult()), getRawStableFunctionTypeRepresentation(fnTy->getRepresentation()), fnTy->isSendable(), fnTy->isAsync(), fnTy->isThrowing(), getRawStableDifferentiabilityKind(fnTy->getDifferentiabilityKind()), S.addTypeRef(fnTy->getGlobalActor()), S.addGenericSignatureRef(genericSig)); serializeFunctionTypeParams(fnTy); } void visitSILBlockStorageType(const SILBlockStorageType *storageTy) { using namespace decls_block; serializeSimpleWrapper( storageTy->getCaptureType()); } void visitSILBoxType(const SILBoxType *boxTy) { using namespace decls_block; unsigned abbrCode = S.DeclTypeAbbrCodes[SILBoxTypeLayout::Code]; SILLayoutID layoutRef = S.addSILLayoutRef(boxTy->getLayout()); SILBoxTypeLayout::emitRecord( S.Out, S.ScratchRecord, abbrCode, layoutRef, S.addSubstitutionMapRef(boxTy->getSubstitutions())); } void visitSILFunctionType(const SILFunctionType *fnTy) { using namespace decls_block; auto representation = fnTy->getRepresentation(); auto stableRepresentation = getRawStableSILFunctionTypeRepresentation(representation); SmallVector variableData; for (auto param : fnTy->getParameters()) { variableData.push_back(S.addTypeRef(param.getInterfaceType())); unsigned conv = getRawStableParameterConvention(param.getConvention()); variableData.push_back(TypeID(conv)); if (fnTy->isDifferentiable()) variableData.push_back(TypeID( getRawSILParameterDifferentiability(param.getDifferentiability()))); } for (auto yield : fnTy->getYields()) { variableData.push_back(S.addTypeRef(yield.getInterfaceType())); unsigned conv = getRawStableParameterConvention(yield.getConvention()); variableData.push_back(TypeID(conv)); } for (auto result : fnTy->getResults()) { variableData.push_back(S.addTypeRef(result.getInterfaceType())); unsigned conv = getRawStableResultConvention(result.getConvention()); variableData.push_back(TypeID(conv)); if (fnTy->isDifferentiable()) variableData.push_back(TypeID( getRawSILResultDifferentiability(result.getDifferentiability()))); } if (fnTy->hasErrorResult()) { auto abResult = fnTy->getErrorResult(); variableData.push_back(S.addTypeRef(abResult.getInterfaceType())); unsigned conv = getRawStableResultConvention(abResult.getConvention()); variableData.push_back(TypeID(conv)); } auto invocationSigID = S.addGenericSignatureRef(fnTy->getInvocationGenericSignature()); auto invocationSubstMapID = S.addSubstitutionMapRef(fnTy->getInvocationSubstitutions()); auto patternSubstMapID = S.addSubstitutionMapRef(fnTy->getPatternSubstitutions()); auto clangTypeID = S.addClangTypeRef(fnTy->getClangTypeInfo().getType()); auto stableCoroutineKind = getRawStableSILCoroutineKind(fnTy->getCoroutineKind()); auto stableCalleeConvention = getRawStableParameterConvention(fnTy->getCalleeConvention()); auto stableDiffKind = getRawStableDifferentiabilityKind(fnTy->getDifferentiabilityKind()); unsigned abbrCode = S.DeclTypeAbbrCodes[SILFunctionTypeLayout::Code]; SILFunctionTypeLayout::emitRecord( S.Out, S.ScratchRecord, abbrCode, fnTy->isSendable(), fnTy->isAsync(), stableCoroutineKind, stableCalleeConvention, stableRepresentation, fnTy->isPseudogeneric(), fnTy->isNoEscape(), stableDiffKind, fnTy->hasErrorResult(), fnTy->getParameters().size(), fnTy->getNumYields(), fnTy->getNumResults(), invocationSigID, invocationSubstMapID, patternSubstMapID, clangTypeID, variableData); if (auto conformance = fnTy->getWitnessMethodConformanceOrInvalid()) S.writeConformance(conformance, S.DeclTypeAbbrCodes); } void visitArraySliceType(const ArraySliceType *sliceTy) { using namespace decls_block; serializeSimpleWrapper(sliceTy->getBaseType()); } void visitDictionaryType(const DictionaryType *dictTy) { using namespace decls_block; unsigned abbrCode = S.DeclTypeAbbrCodes[DictionaryTypeLayout::Code]; DictionaryTypeLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode, S.addTypeRef(dictTy->getKeyType()), S.addTypeRef(dictTy->getValueType())); } void visitOptionalType(const OptionalType *optionalTy) { using namespace decls_block; serializeSimpleWrapper(optionalTy->getBaseType()); } void visitProtocolCompositionType(const ProtocolCompositionType *composition) { using namespace decls_block; SmallVector protocols; for (auto proto : composition->getMembers()) protocols.push_back(S.addTypeRef(proto)); unsigned abbrCode = S.DeclTypeAbbrCodes[ProtocolCompositionTypeLayout::Code]; ProtocolCompositionTypeLayout::emitRecord( S.Out, S.ScratchRecord, abbrCode, composition->hasExplicitAnyObject(), protocols); } void visitReferenceStorageType(const ReferenceStorageType *refTy) { using namespace decls_block; unsigned abbrCode = S.DeclTypeAbbrCodes[ReferenceStorageTypeLayout::Code]; auto stableOwnership = getRawStableReferenceOwnership(refTy->getOwnership()); ReferenceStorageTypeLayout::emitRecord( S.Out, S.ScratchRecord, abbrCode, stableOwnership, S.addTypeRef(refTy->getReferentType())); } void visitUnboundGenericType(const UnboundGenericType *generic) { using namespace decls_block; unsigned abbrCode = S.DeclTypeAbbrCodes[UnboundGenericTypeLayout::Code]; UnboundGenericTypeLayout::emitRecord( S.Out, S.ScratchRecord, abbrCode, S.addDeclRef(generic->getDecl(), /*allowTypeAliasXRef*/true), S.addTypeRef(generic->getParent())); } void visitBoundGenericType(const BoundGenericType *generic) { using namespace decls_block; SmallVector genericArgIDs; for (auto next : generic->getGenericArgs()) genericArgIDs.push_back(S.addTypeRef(next)); unsigned abbrCode = S.DeclTypeAbbrCodes[BoundGenericTypeLayout::Code]; BoundGenericTypeLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode, S.addDeclRef(generic->getDecl()), S.addTypeRef(generic->getParent()), genericArgIDs); } }; void Serializer::writeASTBlockEntity(Type ty) { using namespace decls_block; PrettyStackTraceType traceRAII(ty->getASTContext(), "serializing", ty); assert(TypesToSerialize.hasRef(ty)); BitOffset initialOffset = Out.GetCurrentBitNo(); SWIFT_DEFER { // This is important enough to leave on in Release builds. if (initialOffset == Out.GetCurrentBitNo()) { llvm::PrettyStackTraceString message("failed to serialize anything"); abort(); } }; TypeSerializer(*this).visit(ty); } namespace { class ClangToSwiftBasicWriter : public swift::DataStreamBasicWriter { Serializer &S; SmallVectorImpl &Record; using TypeWriter = clang::serialization::AbstractTypeWriter; TypeWriter Types; ClangModuleLoader *getClangLoader() { return S.getASTContext().getClangModuleLoader(); } public: ClangToSwiftBasicWriter(Serializer &S, SmallVectorImpl &record) : swift::DataStreamBasicWriter( S.getASTContext().getClangModuleLoader()->getClangASTContext()), S(S), Record(record), Types(*this) {} void writeUInt64(uint64_t value) { Record.push_back(value); } void writeIdentifier(const clang::IdentifierInfo *value) { IdentifierID id = 0; if (value) { id = S.addDeclBaseNameRef( S.getASTContext().getIdentifier(value->getName())); } Record.push_back(id); } void writeStmtRef(const clang::Stmt *stmt) { // The deserializer should always read null, and isSerializable // should be checking that we don't see a non-null statement here. if (stmt) { llvm::report_fatal_error("serializing a non-null Clang statement or" " expression reference"); } } void writeDeclRef(const clang::Decl *decl) { if (!decl) { Record.push_back(/*no declaration*/ 0); return; } auto path = getClangLoader()->findStableSerializationPath(decl); if (!path) { decl->dump(llvm::errs()); llvm::report_fatal_error("failed to find a stable Swift serialization" " path for the above Clang declaration"); } if (path.isSwiftDecl()) { Record.push_back(/*swift declaration*/ 1); Record.push_back(S.addDeclRef(path.getSwiftDecl())); return; } assert(path.isExternalPath()); auto &ext = path.getExternalPath(); Record.push_back(/*external path*/ 2); Record.push_back(ext.Path.size()); for (auto &elt : ext.Path) { auto kind = elt.first; auto stableKind = unsigned(getStableClangDeclPathComponentKind(kind)); Record.push_back(stableKind); if (ext.requiresIdentifier(kind)) Record.push_back(S.addDeclBaseNameRef(elt.second)); } } }; } void Serializer::writeASTBlockEntity(const clang::Type *ty) { using namespace decls_block; auto &ctx = getASTContext().getClangModuleLoader()->getClangASTContext(); PrettyStackTraceClangType traceRAII(ctx, "serializing clang type", ty); assert(ClangTypesToSerialize.hasRef(ty)); // Serialize the type as an opaque sequence of data. SmallVector typeData; ClangToSwiftBasicWriter(*this, typeData).writeTypeRef(ty); // Write that in an opaque record. unsigned abbrCode = DeclTypeAbbrCodes[ClangTypeLayout::Code]; ClangTypeLayout::emitRecord(Out, ScratchRecord, abbrCode, typeData); } template bool Serializer::writeASTBlockEntitiesIfNeeded( SpecificASTBlockRecordKeeper &entities) { if (!entities.hasMoreToSerialize()) return false; while (auto next = entities.popNext(Out.GetCurrentBitNo())) writeASTBlockEntity(next.getValue()); return true; } void Serializer::writeAllDeclsAndTypes() { BCBlockRAII restoreBlock(Out, DECLS_AND_TYPES_BLOCK_ID, 8); using namespace decls_block; registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); #define DECL_ATTR(X, NAME, ...) \ registerDeclTypeAbbr(); #include "swift/AST/Attr.def" bool wroteSomething; do { // Each of these loops can trigger the others to execute again, so repeat // until /all/ of the pending lists are empty. wroteSomething = false; wroteSomething |= writeASTBlockEntitiesIfNeeded(DeclsToSerialize); wroteSomething |= writeASTBlockEntitiesIfNeeded(TypesToSerialize); wroteSomething |= writeASTBlockEntitiesIfNeeded(ClangTypesToSerialize); wroteSomething |= writeASTBlockEntitiesIfNeeded(LocalDeclContextsToSerialize); wroteSomething |= writeASTBlockEntitiesIfNeeded(GenericSignaturesToSerialize); wroteSomething |= writeASTBlockEntitiesIfNeeded(SubstitutionMapsToSerialize); wroteSomething |= writeASTBlockEntitiesIfNeeded(NormalConformancesToSerialize); wroteSomething |= writeASTBlockEntitiesIfNeeded(SILLayoutsToSerialize); } while (wroteSomething); } std::vector Serializer::writeAllIdentifiers() { assert(!DeclsToSerialize.hasMoreToSerialize() && "did not call Serializer::writeAllDeclsAndTypes?"); BCBlockRAII restoreBlock(Out, IDENTIFIER_DATA_BLOCK_ID, 3); identifier_block::IdentifierDataLayout IdentifierData(Out); llvm::SmallString<4096> stringData; // Make sure no identifier has an offset of 0. stringData.push_back('\0'); std::vector identifierOffsets; for (StringRef str : StringsToWrite) { identifierOffsets.push_back(stringData.size()); stringData.append(str); stringData.push_back('\0'); } IdentifierData.emit(ScratchRecord, stringData.str()); return identifierOffsets; } template void Serializer::writeOffsets(const index_block::OffsetsLayout &Offsets, const SpecificASTBlockRecordKeeper &entities) { Offsets.emit(ScratchRecord, SpecificASTBlockRecordKeeper::RecordCode, entities.getOffsets()); } /// Writes an in-memory decl table to an on-disk representation, using the /// given layout. static void writeDeclTable(const index_block::DeclListLayout &DeclList, index_block::RecordKind kind, const Serializer::DeclTable &table) { if (table.empty()) return; SmallVector scratch; llvm::SmallString<4096> hashTableBlob; uint32_t tableOffset; { llvm::OnDiskChainedHashTableGenerator generator; for (auto &entry : table) generator.insert(entry.first, entry.second); llvm::raw_svector_ostream blobStream(hashTableBlob); // Make sure that no bucket is at offset 0 endian::write(blobStream, 0, little); tableOffset = generator.Emit(blobStream); } DeclList.emit(scratch, kind, tableOffset, hashTableBlob); } static void writeExtensionTable(const index_block::ExtensionTableLayout &ExtensionTable, const Serializer::ExtensionTable &table, Serializer &serializer) { if (table.empty()) return; SmallVector scratch; llvm::SmallString<4096> hashTableBlob; uint32_t tableOffset; { llvm::OnDiskChainedHashTableGenerator generator; ExtensionTableInfo info{serializer}; for (auto &entry : table) { generator.insert(entry.first, entry.second, info); } llvm::raw_svector_ostream blobStream(hashTableBlob); // Make sure that no bucket is at offset 0 endian::write(blobStream, 0, little); tableOffset = generator.Emit(blobStream, info); } ExtensionTable.emit(scratch, tableOffset, hashTableBlob); } static void writeLocalDeclTable(const index_block::DeclListLayout &DeclList, index_block::RecordKind kind, LocalTypeHashTableGenerator &generator) { SmallVector scratch; llvm::SmallString<4096> hashTableBlob; uint32_t tableOffset; { llvm::raw_svector_ostream blobStream(hashTableBlob); // Make sure that no bucket is at offset 0 endian::write(blobStream, 0, little); tableOffset = generator.Emit(blobStream); } DeclList.emit(scratch, kind, tableOffset, hashTableBlob); } static void writeNestedTypeDeclsTable(const index_block::NestedTypeDeclsLayout &declList, const Serializer::NestedTypeDeclsTable &table) { SmallVector scratch; llvm::SmallString<4096> hashTableBlob; uint32_t tableOffset; { llvm::OnDiskChainedHashTableGenerator generator; for (auto &entry : table) generator.insert(entry.first, entry.second); llvm::raw_svector_ostream blobStream(hashTableBlob); // Make sure that no bucket is at offset 0 endian::write(blobStream, 0, little); tableOffset = generator.Emit(blobStream); } declList.emit(scratch, tableOffset, hashTableBlob); } static void writeDeclMemberNamesTable(const index_block::DeclMemberNamesLayout &declNames, const Serializer::DeclMemberNamesTable &table) { SmallVector scratch; llvm::SmallString<4096> hashTableBlob; uint32_t tableOffset; { llvm::OnDiskChainedHashTableGenerator generator; // Emit the offsets of the sub-tables; the tables themselves have been // separately emitted into DECL_MEMBER_TABLES_BLOCK by now. for (auto &entry : table) { // Or they _should_ have been; check for nonzero offsets. assert(static_cast(entry.second.first) != 0); generator.insert(entry.first, entry.second.first); } llvm::raw_svector_ostream blobStream(hashTableBlob); // Make sure that no bucket is at offset 0 endian::write(blobStream, 0, little); tableOffset = generator.Emit(blobStream); } declNames.emit(scratch, tableOffset, hashTableBlob); } static void writeDeclMembersTable(const decl_member_tables_block::DeclMembersLayout &mems, const Serializer::DeclMembersTable &table) { SmallVector scratch; llvm::SmallString<4096> hashTableBlob; uint32_t tableOffset; { llvm::OnDiskChainedHashTableGenerator generator; for (auto &entry : table) generator.insert(entry.first, entry.second); llvm::raw_svector_ostream blobStream(hashTableBlob); // Make sure that no bucket is at offset 0 endian::write(blobStream, 0, little); tableOffset = generator.Emit(blobStream); } mems.emit(scratch, tableOffset, hashTableBlob); } static void writeDeclFingerprintsTable(const index_block::DeclFingerprintsLayout &fpl, const Serializer::DeclFingerprintsTable &table) { SmallVector scratch; llvm::SmallString<4096> hashTableBlob; uint32_t tableOffset; { llvm::OnDiskChainedHashTableGenerator generator; for (auto &entry : table) { generator.insert(entry.first, entry.second); } llvm::raw_svector_ostream blobStream(hashTableBlob); // Make sure that no bucket is at offset 0 endian::write(blobStream, 0, little); tableOffset = generator.Emit(blobStream); } fpl.emit(scratch, tableOffset, hashTableBlob); } namespace { /// Used to serialize the on-disk Objective-C method hash table. class ObjCMethodTableInfo { public: using key_type = ObjCSelector; using key_type_ref = key_type; using data_type = Serializer::ObjCMethodTableData; using data_type_ref = const data_type &; using hash_value_type = uint32_t; using offset_type = unsigned; hash_value_type ComputeHash(key_type_ref key) { llvm::SmallString<32> scratch; return llvm::djbHash(key.getString(scratch), SWIFTMODULE_HASH_SEED); } std::pair EmitKeyDataLength(raw_ostream &out, key_type_ref key, data_type_ref data) { llvm::SmallString<32> scratch; auto keyLength = key.getString(scratch).size(); assert(keyLength <= std::numeric_limits::max() && "selector too long"); uint32_t dataLength = 0; for (const auto &entry : data) { dataLength += sizeof(uint32_t) + 1 + sizeof(uint32_t); dataLength += std::get<0>(entry).size(); } endian::Writer writer(out, little); writer.write(keyLength); writer.write(dataLength); return { keyLength, dataLength }; } void EmitKey(raw_ostream &out, key_type_ref key, unsigned len) { #ifndef NDEBUG uint64_t start = out.tell(); #endif out << key; assert((out.tell() - start == len) && "measured key length incorrectly"); } void EmitData(raw_ostream &out, key_type_ref key, data_type_ref data, unsigned len) { static_assert(declIDFitsIn32Bits(), "DeclID too large"); endian::Writer writer(out, little); for (const auto &entry : data) { writer.write(std::get<0>(entry).size()); writer.write(std::get<1>(entry)); writer.write(std::get<2>(entry)); out.write(std::get<0>(entry).c_str(), std::get<0>(entry).size()); } } }; } // end anonymous namespace static void writeObjCMethodTable(const index_block::ObjCMethodTableLayout &out, Serializer::ObjCMethodTable &objcMethods) { // Collect all of the Objective-C selectors in the method table. std::vector selectors; for (const auto &entry : objcMethods) { selectors.push_back(entry.first); } // Sort the Objective-C selectors so we emit them in a stable order. llvm::array_pod_sort(selectors.begin(), selectors.end()); // Create the on-disk hash table. llvm::OnDiskChainedHashTableGenerator generator; llvm::SmallString<32> hashTableBlob; uint32_t tableOffset; { llvm::raw_svector_ostream blobStream(hashTableBlob); for (auto selector : selectors) { generator.insert(selector, objcMethods[selector]); } // Make sure that no bucket is at offset 0 endian::write(blobStream, 0, little); tableOffset = generator.Emit(blobStream); } SmallVector scratch; out.emit(scratch, tableOffset, hashTableBlob); } namespace { /// Used to serialize derivative function configurations. class DerivativeFunctionConfigTableInfo { public: using key_type = std::string; using key_type_ref = StringRef; using data_type = Serializer::DerivativeFunctionConfigTableData; using data_type_ref = const data_type &; using hash_value_type = uint32_t; using offset_type = unsigned; hash_value_type ComputeHash(key_type_ref key) { assert(!key.empty()); return llvm::djbHash(key, SWIFTMODULE_HASH_SEED); } std::pair EmitKeyDataLength(raw_ostream &out, key_type_ref key, data_type_ref data) { uint32_t keyLength = key.str().size(); assert(keyLength == static_cast(keyLength)); uint32_t dataLength = (sizeof(uint32_t) * 2) * data.size(); for (auto entry : data) dataLength += entry.first.size(); assert(dataLength == static_cast(dataLength)); endian::Writer writer(out, little); writer.write(keyLength); writer.write(dataLength); return { keyLength, dataLength }; } void EmitKey(raw_ostream &out, key_type_ref key, unsigned len) { out << key; } void EmitData(raw_ostream &out, key_type_ref key, data_type_ref data, unsigned len) { static_assert(declIDFitsIn32Bits(), "DeclID too large"); endian::Writer writer(out, little); for (auto &entry : data) { // Write `GenericSignatureID`. writer.write(entry.second); // Write parameter indices string size, followed by data. writer.write(entry.first.size()); out << entry.first; } } }; } // end anonymous namespace static void writeDerivativeFunctionConfigs( Serializer &S, const index_block::DerivativeFunctionConfigTableLayout &out, Serializer::DerivativeFunctionConfigTable &derivativeConfigs) { // Create the on-disk hash table. llvm::OnDiskChainedHashTableGenerator generator; llvm::SmallString<32> hashTableBlob; uint32_t tableOffset; { llvm::raw_svector_ostream blobStream(hashTableBlob); for (auto &entry : derivativeConfigs) generator.insert(entry.first.get(), entry.second); // Make sure that no bucket is at offset 0. endian::write(blobStream, 0, little); tableOffset = generator.Emit(blobStream); } SmallVector scratch; out.emit(scratch, tableOffset, hashTableBlob); } // Records derivative function configurations for the given AbstractFunctionDecl // by visiting `@differentiable` and `@derivative` attributes. static void recordDerivativeFunctionConfig( Serializer &S, const AbstractFunctionDecl *AFD, Serializer::UniquedDerivativeFunctionConfigTable &derivativeConfigs) { auto &ctx = AFD->getASTContext(); Mangle::ASTMangler Mangler; for (auto *attr : AFD->getAttrs().getAttributes()) { auto mangledName = ctx.getIdentifier(Mangler.mangleDeclAsUSR(AFD, "")); derivativeConfigs[mangledName].insert( {ctx.getIdentifier(attr->getParameterIndices()->getString()), attr->getDerivativeGenericSignature()}); } for (auto *attr : AFD->getAttrs().getAttributes()) { auto *origAFD = attr->getOriginalFunction(ctx); auto mangledName = ctx.getIdentifier(Mangler.mangleDeclAsUSR(origAFD, "")); derivativeConfigs[mangledName].insert( {ctx.getIdentifier(attr->getParameterIndices()->getString()), AFD->getGenericSignature()}); } }; /// Recursively walks the members and derived global decls of any nominal types /// to build up global tables. template static void collectInterestingNestedDeclarations( Serializer &S, Range members, Serializer::DeclTable &operatorMethodDecls, Serializer::ObjCMethodTable &objcMethods, Serializer::NestedTypeDeclsTable &nestedTypeDecls, Serializer::UniquedDerivativeFunctionConfigTable &derivativeConfigs, bool isLocal = false) { const NominalTypeDecl *nominalParent = nullptr; for (const Decl *member : members) { // If there is a corresponding Objective-C method, record it. auto recordObjCMethod = [&](const AbstractFunctionDecl *func) { if (isLocal) return; if (auto owningClass = func->getDeclContext()->getSelfClassDecl()) { if (func->isObjC()) { Mangle::ASTMangler mangler; std::string ownerName = mangler.mangleNominalType(owningClass); assert(!ownerName.empty() && "Mangled type came back empty!"); objcMethods[func->getObjCSelector()].push_back( std::make_tuple(ownerName, func->isObjCInstanceMethod(), S.addDeclRef(func))); } } }; if (auto memberValue = dyn_cast(member)) { if (memberValue->hasName() && memberValue->isOperator()) { // Add operator methods. // Note that we don't have to add operators that are already in the // top-level list. operatorMethodDecls[memberValue->getBaseName()].push_back({ /*ignored*/0, S.addDeclRef(memberValue) }); } } // Record Objective-C methods and derivative function configurations. if (auto *func = dyn_cast(member)) { recordObjCMethod(func); recordDerivativeFunctionConfig(S, func, derivativeConfigs); } // Handle accessors. if (auto storage = dyn_cast(member)) { for (auto *accessor : storage->getAllAccessors()) { recordObjCMethod(accessor); recordDerivativeFunctionConfig(S, accessor, derivativeConfigs); } } if (auto nestedType = dyn_cast(member)) { if (nestedType->getEffectiveAccess() > swift::AccessLevel::FilePrivate) { if (!nominalParent) { const DeclContext *DC = member->getDeclContext(); nominalParent = DC->getSelfNominalTypeDecl(); assert((nominalParent || S.allowCompilerErrors()) && "parent context is not a type or extension"); } nestedTypeDecls[nestedType->getName()].push_back({ S.addDeclRef(nominalParent), S.addDeclRef(nestedType) }); } } // Recurse into nested declarations. if (auto iterable = dyn_cast(member)) { collectInterestingNestedDeclarations(S, iterable->getAllMembers(), operatorMethodDecls, objcMethods, nestedTypeDecls, derivativeConfigs, isLocal); } } } void Serializer::writeAST(ModuleOrSourceFile DC) { DeclTable topLevelDecls, operatorDecls, operatorMethodDecls; DeclTable precedenceGroupDecls; ObjCMethodTable objcMethods; NestedTypeDeclsTable nestedTypeDecls; LocalTypeHashTableGenerator localTypeGenerator, opaqueReturnTypeGenerator; ExtensionTable extensionDecls; UniquedDerivativeFunctionConfigTable uniquedDerivativeConfigs; DeclFingerprintsTable declFingerprints; bool hasLocalTypes = false; bool hasOpaqueReturnTypes = false; Optional entryPointClassID; SmallVector orderedTopLevelDecls; ArrayRef files; SmallVector Scratch; if (SF) { Scratch.push_back(SF); if (auto *synthesizedFile = SF->getSynthesizedFile()) Scratch.push_back(synthesizedFile); files = llvm::makeArrayRef(Scratch); } else { files = M->getFiles(); } for (auto nextFile : files) { if (nextFile->hasEntryPoint()) entryPointClassID = addDeclRef(nextFile->getMainDecl()); // FIXME: Switch to a visitor interface? SmallVector fileDecls; nextFile->getTopLevelDecls(fileDecls); for (auto D : fileDecls) { if (isa(D) || isa(D) || isa(D) || isa(D)) { continue; } if (auto VD = dyn_cast(D)) { if (!VD->hasName()) continue; topLevelDecls[VD->getBaseName()] .push_back({ getKindForTable(D), addDeclRef(D) }); } else if (auto ED = dyn_cast(D)) { const NominalTypeDecl *extendedNominal = ED->getExtendedNominal(); if (extendedNominal) { extensionDecls[extendedNominal->getName()] .push_back({ extendedNominal, addDeclRef(D) }); } } else if (auto OD = dyn_cast(D)) { operatorDecls[OD->getName()] .push_back({ getStableFixity(OD->getFixity()), addDeclRef(D) }); } else if (auto PGD = dyn_cast(D)) { precedenceGroupDecls[PGD->getName()] .push_back({ decls_block::PRECEDENCE_GROUP_DECL, addDeclRef(D) }); } else if (isa(D)) { // No special handling needed. } else { llvm_unreachable("all top-level declaration kinds accounted for"); } if (auto *AFD = dyn_cast(D)) recordDerivativeFunctionConfig(*this, AFD, uniquedDerivativeConfigs); orderedTopLevelDecls.push_back(addDeclRef(D)); // If this nominal type has associated top-level decls for a // derived conformance (for example, ==), force them to be // serialized. if (auto IDC = dyn_cast(D)) { if (auto bodyFP = IDC->getBodyFingerprint()) { declFingerprints.insert({addDeclRef(D), *bodyFP}); } collectInterestingNestedDeclarations(*this, IDC->getAllMembers(), operatorMethodDecls, objcMethods, nestedTypeDecls, uniquedDerivativeConfigs); } } SmallVector localTypeDecls; nextFile->getLocalTypeDecls(localTypeDecls); SmallVector opaqueReturnTypeDecls; nextFile->getOpaqueReturnTypeDecls(opaqueReturnTypeDecls); for (auto TD : localTypeDecls) { // FIXME: We should delay parsing function bodies so these type decls // don't even get added to the file. if (TD->getDeclContext()->getInnermostSkippedFunctionContext()) continue; hasLocalTypes = true; Mangle::ASTMangler Mangler; std::string MangledName = evaluateOrDefault(M->getASTContext().evaluator, MangleLocalTypeDeclRequest { TD }, std::string()); assert(!MangledName.empty() && "Mangled type came back empty!"); localTypeGenerator.insert(MangledName, addDeclRef(TD)); if (auto IDC = dyn_cast(TD)) { if (auto bodyFP = IDC->getBodyFingerprint()) { declFingerprints.insert({addDeclRef(TD), *bodyFP}); } collectInterestingNestedDeclarations(*this, IDC->getAllMembers(), operatorMethodDecls, objcMethods, nestedTypeDecls, uniquedDerivativeConfigs, /*isLocal=*/true); } } for (auto OTD : opaqueReturnTypeDecls) { // FIXME: We should delay parsing function bodies so these type decls // don't even get added to the file. if (OTD->getDeclContext()->getInnermostSkippedFunctionContext()) continue; hasOpaqueReturnTypes = true; Mangle::ASTMangler Mangler; auto MangledName = Mangler.mangleOpaqueTypeDecl(OTD); opaqueReturnTypeGenerator.insert(MangledName, addDeclRef(OTD)); } } writeAllDeclsAndTypes(); std::vector identifierOffsets = writeAllIdentifiers(); { BCBlockRAII restoreBlock(Out, INDEX_BLOCK_ID, 4); index_block::OffsetsLayout Offsets(Out); writeOffsets(Offsets, DeclsToSerialize); writeOffsets(Offsets, TypesToSerialize); writeOffsets(Offsets, ClangTypesToSerialize); writeOffsets(Offsets, LocalDeclContextsToSerialize); writeOffsets(Offsets, GenericSignaturesToSerialize); writeOffsets(Offsets, SubstitutionMapsToSerialize); writeOffsets(Offsets, NormalConformancesToSerialize); writeOffsets(Offsets, SILLayoutsToSerialize); Offsets.emit(ScratchRecord, index_block::IDENTIFIER_OFFSETS, identifierOffsets); index_block::DeclListLayout DeclList(Out); writeDeclTable(DeclList, index_block::TOP_LEVEL_DECLS, topLevelDecls); writeDeclTable(DeclList, index_block::OPERATORS, operatorDecls); writeDeclTable(DeclList, index_block::PRECEDENCE_GROUPS, precedenceGroupDecls); writeDeclTable(DeclList, index_block::CLASS_MEMBERS_FOR_DYNAMIC_LOOKUP, ClassMembersForDynamicLookup); writeDeclTable(DeclList, index_block::OPERATOR_METHODS, operatorMethodDecls); if (hasLocalTypes) writeLocalDeclTable(DeclList, index_block::LOCAL_TYPE_DECLS, localTypeGenerator); if (hasOpaqueReturnTypes) writeLocalDeclTable(DeclList, index_block::OPAQUE_RETURN_TYPE_DECLS, opaqueReturnTypeGenerator); if (!extensionDecls.empty()) { index_block::ExtensionTableLayout ExtensionTable(Out); writeExtensionTable(ExtensionTable, extensionDecls, *this); } index_block::OrderedDeclsLayout OrderedDecls(Out); OrderedDecls.emit(ScratchRecord, index_block::ORDERED_TOP_LEVEL_DECLS, orderedTopLevelDecls); index_block::OrderedDeclsLayout ExportedPrespecializationDecls(Out); ExportedPrespecializationDecls.emit( ScratchRecord, index_block::EXPORTED_PRESPECIALIZATION_DECLS, exportedPrespecializationDecls); index_block::ObjCMethodTableLayout ObjCMethodTable(Out); writeObjCMethodTable(ObjCMethodTable, objcMethods); if (!nestedTypeDecls.empty()) { index_block::NestedTypeDeclsLayout NestedTypeDeclsTable(Out); writeNestedTypeDeclsTable(NestedTypeDeclsTable, nestedTypeDecls); } if (!declFingerprints.empty()) { index_block::DeclFingerprintsLayout DeclsFingerprints(Out); writeDeclFingerprintsTable(DeclsFingerprints, declFingerprints); } // Convert uniqued derivative function config table to serialization- // ready format: turn `GenericSignature` to `GenericSignatureID`. DerivativeFunctionConfigTable derivativeConfigs; for (auto entry : uniquedDerivativeConfigs) { for (auto config : entry.second) { std::string paramIndices = config.first.str().str(); auto genSigID = addGenericSignatureRef(config.second); derivativeConfigs[entry.first].push_back( {std::string(paramIndices), genSigID}); } } index_block::DerivativeFunctionConfigTableLayout DerivativeConfigTable(Out); writeDerivativeFunctionConfigs(*this, DerivativeConfigTable, derivativeConfigs); if (entryPointClassID.hasValue()) { index_block::EntryPointLayout EntryPoint(Out); EntryPoint.emit(ScratchRecord, entryPointClassID.getValue()); } { // Write sub-tables to a skippable sub-block. BCBlockRAII restoreBlock(Out, DECL_MEMBER_TABLES_BLOCK_ID, 4); decl_member_tables_block::DeclMembersLayout DeclMembersTable(Out); for (auto &entry : DeclMemberNames) { // Save BitOffset we're writing sub-table to. static_assert(bitOffsetFitsIn32Bits(), "BitOffset too large"); assert(Out.GetCurrentBitNo() < (1ull << 32)); entry.second.first = Out.GetCurrentBitNo(); // Write sub-table. writeDeclMembersTable(DeclMembersTable, *entry.second.second); } } // Write top-level table mapping names to sub-tables. index_block::DeclMemberNamesLayout DeclMemberNamesTable(Out); writeDeclMemberNamesTable(DeclMemberNamesTable, DeclMemberNames); } } void SerializerBase::writeToStream(raw_ostream &os) { os.write(Buffer.data(), Buffer.size()); os.flush(); } SerializerBase::SerializerBase(ArrayRef signature, ModuleOrSourceFile DC) { for (unsigned char byte : signature) Out.Emit(byte, 8); this->M = getModule(DC); this->SF = DC.dyn_cast(); } void Serializer::writeToStream( raw_ostream &os, ModuleOrSourceFile DC, const SILModule *SILMod, const SerializationOptions &options, const fine_grained_dependencies::SourceFileDepGraph *DepGraph) { Serializer S{SWIFTMODULE_SIGNATURE, DC}; // FIXME: This is only really needed for debugging. We don't actually use it. S.writeBlockInfoBlock(); { BCBlockRAII moduleBlock(S.Out, MODULE_BLOCK_ID, 2); S.writeHeader(options); S.writeInputBlock(options); S.writeSIL(SILMod, options.SerializeAllSIL); S.writeAST(DC); if (!options.DisableCrossModuleIncrementalInfo && DepGraph) { fine_grained_dependencies::writeFineGrainedDependencyGraph( S.Out, *DepGraph, fine_grained_dependencies::Purpose::ForSwiftModule); } } S.writeToStream(os); } bool Serializer::allowCompilerErrors() const { return getASTContext().LangOpts.AllowModuleWithCompilerErrors; } void swift::serializeToBuffers( ModuleOrSourceFile DC, const SerializationOptions &options, std::unique_ptr *moduleBuffer, std::unique_ptr *moduleDocBuffer, std::unique_ptr *moduleSourceInfoBuffer, const SILModule *M) { assert(!StringRef::withNullAsEmpty(options.OutputPath).empty()); { FrontendStatsTracer tracer(getContext(DC).Stats, "Serialization, swiftmodule, to buffer"); llvm::SmallString<1024> buf; llvm::raw_svector_ostream stream(buf); Serializer::writeToStream(stream, DC, M, options, /*dependency info*/ nullptr); bool hadError = withOutputFile(getContext(DC).Diags, options.OutputPath, [&](raw_ostream &out) { out << stream.str(); return false; }); if (hadError) return; if (moduleBuffer) *moduleBuffer = std::make_unique( std::move(buf), options.OutputPath); } if (!StringRef::withNullAsEmpty(options.DocOutputPath).empty()) { FrontendStatsTracer tracer(getContext(DC).Stats, "Serialization, swiftdoc, to buffer"); llvm::SmallString<1024> buf; llvm::raw_svector_ostream stream(buf); writeDocToStream(stream, DC, options.GroupInfoPath); (void)withOutputFile(getContext(DC).Diags, options.DocOutputPath, [&](raw_ostream &out) { out << stream.str(); return false; }); if (moduleDocBuffer) *moduleDocBuffer = std::make_unique( std::move(buf), options.DocOutputPath); } if (!StringRef::withNullAsEmpty(options.SourceInfoOutputPath).empty()) { FrontendStatsTracer tracer(getContext(DC).Stats, "Serialization, swiftsourceinfo, to buffer"); llvm::SmallString<1024> buf; llvm::raw_svector_ostream stream(buf); writeSourceInfoToStream(stream, DC); (void)withOutputFile(getContext(DC).Diags, options.SourceInfoOutputPath, [&](raw_ostream &out) { out << stream.str(); return false; }); if (moduleSourceInfoBuffer) *moduleSourceInfoBuffer = std::make_unique( std::move(buf), options.SourceInfoOutputPath); } } void swift::serialize(ModuleOrSourceFile DC, const SerializationOptions &options, const SILModule *M, const fine_grained_dependencies::SourceFileDepGraph *DG) { assert(!StringRef::withNullAsEmpty(options.OutputPath).empty()); if (StringRef(options.OutputPath) == "-") { // Special-case writing to stdout. Serializer::writeToStream(llvm::outs(), DC, M, options, DG); assert(StringRef::withNullAsEmpty(options.DocOutputPath).empty()); return; } bool hadError = withOutputFile(getContext(DC).Diags, options.OutputPath, [&](raw_ostream &out) { FrontendStatsTracer tracer(getContext(DC).Stats, "Serialization, swiftmodule"); Serializer::writeToStream(out, DC, M, options, DG); return false; }); if (hadError) return; if (!StringRef::withNullAsEmpty(options.DocOutputPath).empty()) { (void)withOutputFile(getContext(DC).Diags, options.DocOutputPath, [&](raw_ostream &out) { FrontendStatsTracer tracer(getContext(DC).Stats, "Serialization, swiftdoc"); writeDocToStream(out, DC, options.GroupInfoPath); return false; }); } if (!StringRef::withNullAsEmpty(options.SourceInfoOutputPath).empty()) { (void)withOutputFile(getContext(DC).Diags, options.SourceInfoOutputPath, [&](raw_ostream &out) { FrontendStatsTracer tracer(getContext(DC).Stats, "Serialization, swiftsourceinfo"); writeSourceInfoToStream(out, DC); return false; }); } if (!options.SymbolGraphOutputDir.empty()) { if (DC.is()) { auto *M = DC.get(); FrontendStatsTracer tracer(getContext(DC).Stats, "Serialization, symbolgraph"); symbolgraphgen::SymbolGraphOptions SGOpts { options.SymbolGraphOutputDir, M->getASTContext().LangOpts.Target, /* PrettyPrint */false, AccessLevel::Public, /*EmitSynthesizedMembers*/true, /*PrintMessages*/false, /*EmitInheritedDocs*/options.SkipSymbolGraphInheritedDocs, }; symbolgraphgen::emitSymbolGraphForModule(M, SGOpts); } } }