//===--- 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/DiagnosticsCommon.h" #include "swift/AST/Expr.h" #include "swift/AST/FileSystem.h" #include "swift/AST/ForeignErrorConvention.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/Initializer.h" #include "swift/AST/LinkLibrary.h" #include "swift/AST/ParameterList.h" #include "swift/AST/Pattern.h" #include "swift/AST/PrettyStackTrace.h" #include "swift/AST/ProtocolConformance.h" #include "swift/AST/RawComment.h" #include "swift/AST/TypeCheckRequests.h" #include "swift/Basic/Dwarf.h" #include "swift/Basic/FileSystem.h" #include "swift/Basic/STLExtras.h" #include "swift/Basic/Timer.h" #include "swift/Basic/Version.h" #include "swift/ClangImporter/ClangImporter.h" #include "swift/ClangImporter/ClangModule.h" #include "swift/Serialization/SerializationOptions.h" #include "swift/Strings.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Bitcode/BitstreamWriter.h" #include "llvm/Bitcode/RecordLayout.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/raw_ostream.h" #include "llvm/Support/SmallVectorMemoryBuffer.h" #include using namespace swift; using namespace swift::serialization; using namespace llvm::support; using swift::version::Version; using llvm::BCBlockRAII; /// 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()); // FIXME: DJB seed=0, audit whether the default seed could be used. return llvm::djbHash(key.getIdentifier().str(), 0); 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()); // FIXME: DJB seed=0, audit whether the default seed could be used. return llvm::djbHash(key.str(), 0); } int32_t getNameDataForBase(const NominalTypeDecl *nominal, StringRef *dataToWrite = nullptr) { if (nominal->getDeclContext()->isModuleScopeContext()) return -Serializer.addModuleRef(nominal->getParentModule()); 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()); // FIXME: DJB seed=0, audit whether the default seed could be used. return llvm::djbHash(key, 0); } 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()); // FIXME: DJB seed=0, audit whether the default seed could be used. return llvm::djbHash(key.str(), 0); } 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()); // FIXME: DJB seed=0, audit whether the default seed could be used. return llvm::djbHash(key.getIdentifier().str(), 0); 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); } } }; } // end anonymous namespace namespace llvm { template<> struct DenseMapInfo { using DeclTypeUnion = Serializer::DeclTypeUnion; static inline DeclTypeUnion getEmptyKey() { return nullptr; } static inline DeclTypeUnion getTombstoneKey() { return swift::Type(); } static unsigned getHashValue(const DeclTypeUnion &val) { return DenseMapInfo::getHashValue(val.getOpaqueValue()); } static bool isEqual(const DeclTypeUnion &lhs, const DeclTypeUnion &rhs) { return lhs == rhs; } }; } // namespace llvm 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); } static const Decl *getDeclForContext(const DeclContext *DC) { switch (DC->getContextKind()) { case DeclContextKind::Module: // Use a null decl to represent the module. return nullptr; case DeclContextKind::FileUnit: return getDeclForContext(DC->getParent()); case DeclContextKind::SerializedLocal: llvm_unreachable("Serialized local contexts should only come from deserialization"); case DeclContextKind::Initializer: case DeclContextKind::AbstractClosureExpr: // FIXME: What about default functions? llvm_unreachable("shouldn't serialize decls from anonymous closures"); case DeclContextKind::GenericTypeDecl: return cast(DC); case DeclContextKind::ExtensionDecl: return cast(DC); case DeclContextKind::TopLevelCodeDecl: llvm_unreachable("shouldn't serialize the main module"); case DeclContextKind::AbstractFunctionDecl: return cast(DC); case DeclContextKind::SubscriptDecl: return cast(DC); case DeclContextKind::EnumElementDecl: return cast(DC); } llvm_unreachable("Unhandled DeclContextKind in switch."); } 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) #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; } DeclID Serializer::addLocalDeclContextRef(const DeclContext *DC) { assert(DC->isLocalContext() && "Expected a local DeclContext"); auto &id = LocalDeclContextIDs[DC]; if (id != 0) return id; id = ++LastLocalDeclContextID; LocalDeclContextsToWrite.push(DC); return id; } GenericSignatureID Serializer::addGenericSignatureRef( const GenericSignature *env) { if (!env) return 0; auto &id = GenericSignatureIDs[env]; if (id != 0) return id; id = ++LastGenericSignatureID; GenericSignaturesToWrite.push(env); return id; } GenericEnvironmentID Serializer::addGenericEnvironmentRef( const GenericEnvironment *env) { if (!env) return 0; auto &id = GenericEnvironmentIDs[env]; if (id != 0) return id; id = ++LastGenericEnvironmentID; GenericEnvironmentsToWrite.push(env); return id; } SubstitutionMapID Serializer::addSubstitutionMapRef( SubstitutionMap substitutions) { if (!substitutions) return 0; auto &id = SubstitutionMapIDs[substitutions]; if (id != 0) return id; id = ++LastSubstitutionMapID; SubstitutionMapsToWrite.push(substitutions); return id; } DeclContextID Serializer::addDeclContextRef(const DeclContext *DC) { switch (DC->getContextKind()) { case DeclContextKind::Module: case DeclContextKind::FileUnit: // Skip up to the module return 0; default: break; } // If this decl context is a plain old serializable decl, queue it up for // normal serialization. if (shouldSerializeAsLocalContext(DC)) addLocalDeclContextRef(DC); else addDeclRef(getDeclForContext(DC)); auto &id = DeclContextIDs[DC]; if (id) return id; id = ++LastDeclContextID; DeclContextsToWrite.push(DC); return id; } DeclID Serializer::addDeclRef(const Decl *D, bool allowTypeAliasXRef) { if (!D) return 0; DeclID &id = DeclAndTypeIDs[D]; if (id != 0) return id; assert((!isDeclXRef(D) || isa(D) || isa(D) || isa(D)) && "cannot cross-reference this decl"); assert((!isDeclXRef(D) || !D->getAttrs().hasAttribute()) && "cannot cross-reference this decl"); assert((allowTypeAliasXRef || !isa(D) || D->getModuleContext() == M) && "cannot cross-reference typealiases directly (use the TypeAliasType)"); id = ++LastDeclID; DeclsAndTypesToWrite.push(D); return id; } serialization::TypeID Serializer::addTypeRef(Type ty) { if (!ty) return 0; #ifndef NDEBUG PrettyStackTraceType trace(M->getASTContext(), "serializing", ty); assert(!ty->hasError() && "Serializing error type"); #endif auto &id = DeclAndTypeIDs[ty]; if (id != 0) return id; id = ++LastTypeID; DeclsAndTypesToWrite.push(ty); return id; } 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::addModuleRef(const ModuleDecl *M) { 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; // If we're referring to a member of a private module that will be // re-exported via a public module, record the public module's name. if (auto clangModuleUnit = dyn_cast(M->getFiles().front())) { auto exportedModuleName = M->getASTContext().getIdentifier( clangModuleUnit->getExportedModuleName()); return addDeclBaseNameRef(exportedModuleName); } assert(!M->getName().empty()); return addDeclBaseNameRef(M->getName()); } SILLayoutID Serializer::addSILLayoutRef(SILLayout *layout) { auto &id = SILLayouts[layout]; if (id != 0) return id; id = ++LastSILLayoutID; SILLayoutsToWrite.push(layout); return id; } NormalConformanceID Serializer::addConformanceRef( const NormalProtocolConformance *conformance) { assert(conformance->getDeclContext()->getParentModule() == M && "cannot reference conformance from another module"); auto &conformanceID = NormalConformances[conformance]; if (conformanceID) return conformanceID; conformanceID = ++LastNormalConformanceID; NormalConformancesToWrite.push(conformance); return conformanceID; } /// 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(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(DECLS_AND_TYPES_BLOCK); #define RECORD(X) BLOCK_RECORD(decls_block, X); #include "swift/Serialization/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, ENTRY_POINT); BLOCK_RECORD(index_block, LOCAL_DECL_CONTEXT_OFFSETS); BLOCK_RECORD(index_block, GENERIC_SIGNATURE_OFFSETS); BLOCK_RECORD(index_block, GENERIC_ENVIRONMENT_OFFSETS); BLOCK_RECORD(index_block, SUBSTITUTION_MAP_OFFSETS); BLOCK_RECORD(index_block, DECL_CONTEXT_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, ORDERED_TOP_LEVEL_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_INST_CAST); 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); #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(); Metadata.emit(ScratchRecord, SWIFTMODULE_VERSION_MAJOR, SWIFTMODULE_VERSION_MINOR, shortVersionStringLength, compatibilityVersionStringLength, 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 (M->isTestingEnabled()) { options_block::IsTestableLayout IsTestable(Out); IsTestable.emit(ScratchRecord); } if (M->arePrivateImportsEnabled()) { options_block::ArePrivateImportsEnabledLayout PrivateImports(Out); PrivateImports.emit(ScratchRecord); } if (M->getResilienceStrategy() != ResilienceStrategy::Default) { options_block::ResilienceStrategyLayout Strategy(Out); Strategy.emit(ScratchRecord, unsigned(M->getResilienceStrategy())); } 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); } } } } } using ImportPathBlob = llvm::SmallString<64>; static void flattenImportPath(const ModuleDecl::ImportedModule &import, ImportPathBlob &out) { SmallVector reverseSubmoduleNames( import.second->getReverseFullModuleName(), {}); interleave(reverseSubmoduleNames.rbegin(), reverseSubmoduleNames.rend(), [&out](StringRef next) { out.append(next); }, [&out] { out.push_back('\0'); }); if (import.first.empty()) return; out.push_back('\0'); assert(import.first.size() == 1 && "can only handle top-level decl imports"); auto accessPathElem = import.first.front(); out.append(accessPathElem.first.str()); } uint64_t getRawModTimeOrHash(const SerializationOptions::FileDependency &dep) { if (dep.isHashBased()) return dep.getContentHash(); return dep.getModificationTime(); } void Serializer::writeInputBlock(const SerializationOptions &options) { BCBlockRAII restoreBlock(Out, INPUT_BLOCK_ID, 4); input_block::ImportedModuleLayout ImportedModule(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); 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); } for (auto const &dep : options.Dependencies) { FileDependency.emit(ScratchRecord, dep.getSize(), getRawModTimeOrHash(dep), dep.isHashBased(), dep.getPath()); } SmallVector allImports; M->getImportedModules(allImports, ModuleDecl::ImportFilter::All); ModuleDecl::removeDuplicateImports(allImports); // Collect the public imports as a subset so that we can mark them with an // extra flag. SmallVector publicImports; M->getImportedModules(publicImports, ModuleDecl::ImportFilter::Public); llvm::SmallSet publicImportSet; publicImportSet.insert(publicImports.begin(), publicImports.end()); auto clangImporter = static_cast(M->getASTContext().getClangModuleLoader()); ModuleDecl *bridgingHeaderModule = clangImporter->getImportedHeaderModule(); ModuleDecl::ImportedModule bridgingHeaderImport{{}, 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.second == theBuiltinModule || import.second == bridgingHeaderModule) { continue; } ImportPathBlob importPath; flattenImportPath(import, importPath); ImportedModule.emit(ScratchRecord, publicImportSet.count(import), !import.first.empty(), importPath); } 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(File) CASE(Line) CASE(Function) CASE(DSOHandle) CASE(NilLiteral) CASE(EmptyArray) CASE(EmptyDictionary) #undef CASE } llvm_unreachable("Unhandled DefaultArgumentKind in switch."); } static uint8_t getRawStableMetatypeRepresentation(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"); } static uint8_t getRawStableResilienceExpansion(swift::ResilienceExpansion e) { switch (e) { case swift::ResilienceExpansion::Minimal: return uint8_t(serialization::ResilienceExpansion::Minimal); case swift::ResilienceExpansion::Maximal: return uint8_t(serialization::ResilienceExpansion::Maximal); } llvm_unreachable("unhandled expansion"); } void Serializer::writeParameterList(const ParameterList *PL) { using namespace decls_block; SmallVector paramIDs; for (const ParamDecl *param : *PL) paramIDs.push_back(addDeclRef(param)); unsigned abbrCode = DeclTypeAbbrCodes[ParameterListLayout::Code]; ParameterListLayout::emitRecord(Out, ScratchRecord, abbrCode, paramIDs); } void Serializer::writePattern(const Pattern *pattern, DeclContext *owningDC) { using namespace decls_block; // Retrieve the type of the pattern. auto getPatternType = [&] { Type type = pattern->getType(); // If we have an owning context and a contextual type, map out to an // interface type. if (owningDC && type->hasArchetype()) type = type->mapTypeOutOfContext(); return type; }; assert(pattern && "null pattern"); switch (pattern->getKind()) { case PatternKind::Paren: { unsigned abbrCode = DeclTypeAbbrCodes[ParenPatternLayout::Code]; ParenPatternLayout::emitRecord(Out, ScratchRecord, abbrCode, pattern->isImplicit()); writePattern(cast(pattern)->getSubPattern(), owningDC); break; } case PatternKind::Tuple: { auto tuple = cast(pattern); unsigned abbrCode = DeclTypeAbbrCodes[TuplePatternLayout::Code]; TuplePatternLayout::emitRecord(Out, ScratchRecord, abbrCode, addTypeRef(getPatternType()), tuple->getNumElements(), tuple->isImplicit()); abbrCode = DeclTypeAbbrCodes[TuplePatternEltLayout::Code]; for (auto &elt : tuple->getElements()) { // FIXME: Default argument expressions? TuplePatternEltLayout::emitRecord( Out, ScratchRecord, abbrCode, addDeclBaseNameRef(elt.getLabel())); writePattern(elt.getPattern(), owningDC); } break; } case PatternKind::Named: { auto named = cast(pattern); unsigned abbrCode = DeclTypeAbbrCodes[NamedPatternLayout::Code]; NamedPatternLayout::emitRecord(Out, ScratchRecord, abbrCode, addDeclRef(named->getDecl()), addTypeRef(getPatternType()), named->isImplicit()); break; } case PatternKind::Any: { unsigned abbrCode = DeclTypeAbbrCodes[AnyPatternLayout::Code]; AnyPatternLayout::emitRecord(Out, ScratchRecord, abbrCode, addTypeRef(getPatternType()), pattern->isImplicit()); break; } case PatternKind::Typed: { auto typed = cast(pattern); unsigned abbrCode = DeclTypeAbbrCodes[TypedPatternLayout::Code]; TypedPatternLayout::emitRecord(Out, ScratchRecord, abbrCode, addTypeRef(getPatternType()), typed->isImplicit()); writePattern(typed->getSubPattern(), owningDC); 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::Var: { auto var = cast(pattern); unsigned abbrCode = DeclTypeAbbrCodes[VarPatternLayout::Code]; VarPatternLayout::emitRecord(Out, ScratchRecord, abbrCode, var->isLet(), var->isImplicit()); writePattern(var->getSubPattern(), owningDC); break; } } } /// 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::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 parseable interface after // merging them. if (!SF) return; if (AFD->getResilienceExpansion() != swift::ResilienceExpansion::Minimal) return; if (!AFD->hasInlinableBodyText()) return; SmallString<128> scratch; auto body = AFD->getInlinableBodyText(scratch); unsigned abbrCode = DeclTypeAbbrCodes[InlinableBodyTextLayout::Code]; InlinableBodyTextLayout::emitRecord(Out, ScratchRecord, abbrCode, body); } void Serializer::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(addDeclRef(next)); unsigned abbrCode = DeclTypeAbbrCodes[GenericParamListLayout::Code]; GenericParamListLayout::emitRecord(Out, ScratchRecord, abbrCode, paramIDs); } void Serializer::writeGenericSignature(const GenericSignature *sig) { using namespace decls_block; // Record the offset of this generic environment. auto id = GenericSignatureIDs[sig]; assert(id != 0 && "generic signature not referenced properly"); (void)id; assert((id - 1) == GenericSignatureOffsets.size()); GenericSignatureOffsets.push_back(Out.GetCurrentBitNo()); assert(sig != nullptr); // 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); writeGenericRequirements(sig->getRequirements(), DeclTypeAbbrCodes); } void Serializer::writeGenericEnvironment(const GenericEnvironment *env) { using namespace decls_block; // Record the offset of this generic environment. auto id = GenericEnvironmentIDs[env]; assert(id != 0 && "generic environment not referenced properly"); (void)id; assert((id - 1) == GenericEnvironmentOffsets.size()); assert(env != nullptr); // Determine whether we must use SIL mode, because one of the generic // parameters has a declaration with module context. bool SILMode = false; for (auto *paramTy : env->getGenericParams()) { if (auto *decl = paramTy->getDecl()) { if (decl->getDeclContext()->isModuleScopeContext()) { SILMode = true; break; } } } // If not in SIL mode, generic environments just contain a reference to // the generic signature. if (!SILMode) { // Record the generic signature directly. auto genericSigID = addGenericSignatureRef(env->getGenericSignature()); GenericEnvironmentOffsets.push_back((genericSigID << 1) | 0x01); return; } // Record the current bit. GenericEnvironmentOffsets.push_back((Out.GetCurrentBitNo() << 1)); // Record the generic parameters. SmallVector rawParamIDs; for (auto *paramTy : env->getGenericParams()) { auto *decl = paramTy->getDecl(); // In SIL mode, add the name and canonicalize the parameter type. if (decl) rawParamIDs.push_back(addDeclBaseNameRef(decl->getName())); else rawParamIDs.push_back(addDeclBaseNameRef(Identifier())); paramTy = paramTy->getCanonicalType()->castTo(); rawParamIDs.push_back(addTypeRef(paramTy)); } auto envAbbrCode = DeclTypeAbbrCodes[SILGenericEnvironmentLayout::Code]; SILGenericEnvironmentLayout::emitRecord(Out, ScratchRecord, envAbbrCode, rawParamIDs); writeGenericRequirements(env->getGenericSignature()->getRequirements(), DeclTypeAbbrCodes); } void Serializer::writeSubstitutionMap(const SubstitutionMap substitutions) { using namespace decls_block; assert(substitutions); // Record the offset of this substitution map. auto id = SubstitutionMapIDs[substitutions]; assert(id != 0 && "generic environment not referenced properly"); (void)id; // Record the current bit. assert((id - 1) == SubstitutionMapOffsets.size()); SubstitutionMapOffsets.push_back(Out.GetCurrentBitNo()); // 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::writeSILLayout(SILLayout *layout) { using namespace decls_block; auto foundLayoutID = SILLayouts.find(layout); assert(foundLayoutID != SILLayouts.end() && "layout not referenced properly"); assert(foundLayoutID->second - 1 == SILLayoutOffsets.size()); (void) foundLayoutID; SILLayoutOffsets.push_back(Out.GetCurrentBitNo()); 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::writeNormalConformance( const NormalProtocolConformance *conformance) { using namespace decls_block; // The conformance must be complete, or we can't serialize it. assert(conformance->isComplete()); auto conformanceID = NormalConformances[conformance]; assert(conformanceID != 0 && "normal conformance not referenced properly"); (void)conformanceID; assert((conformanceID - 1) == NormalConformanceOffsets.size()); NormalConformanceOffsets.push_back(Out.GetCurrentBitNo()); auto protocol = conformance->getProtocol(); SmallVector data; unsigned numValueWitnesses = 0; unsigned numTypeWitnesses = 0; conformance->forEachTypeWitness(/*resolver=*/nullptr, [&](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(nullptr, [&](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())); // 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, 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(getDeclForContext(normal->getDeclContext())) && !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()), addModuleRef(normal->getDeclContext()->getParentModule())); } 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 uint8_t getRawStableOptionalTypeKind(swift::OptionalTypeKind kind) { switch (kind) { case swift::OTK_None: return static_cast(serialization::OptionalTypeKind::None); case swift::OTK_Optional: return static_cast(serialization::OptionalTypeKind::Optional); case swift::OTK_ImplicitlyUnwrappedOptional: return static_cast( serialization::OptionalTypeKind::ImplicitlyUnwrappedOptional); } llvm_unreachable("Unhandled OptionalTypeKind in switch."); } 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: llvm_unreachable("decl should never be a member"); case DeclKind::MissingMember: 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::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."); } void Serializer::writeMembers(DeclID parentID, DeclRange members, bool isClass) { using namespace decls_block; unsigned abbrCode = DeclTypeAbbrCodes[MembersLayout::Code]; SmallVector memberIDs; for (auto member : members) { if (!shouldSerializeMember(member)) continue; DeclID memberID = 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 = DeclMemberNames[VD->getBaseName()].second; if (!memberTable) { memberTable = llvm::make_unique(); } (*memberTable)[parentID].push_back(memberID); } // Same as above, but for @_implements attributes if (auto A = VD->getAttrs().getAttribute()) { std::unique_ptr &memberTable = DeclMemberNames[A->getMemberName().getBaseName()].second; if (!memberTable) { memberTable = llvm::make_unique(); } (*memberTable)[parentID].push_back(memberID); } // Possibly add a record to ClassMembersForDynamicLookup too. if (isClass) { if (VD->canBeAccessedByDynamicLookup()) { auto &list = ClassMembersForDynamicLookup[VD->getBaseName()]; list.push_back({getKindForTable(VD), memberID}); } } } } MembersLayout::emitRecord(Out, ScratchRecord, abbrCode, memberIDs); } void Serializer::writeDefaultWitnessTable(const ProtocolDecl *proto, const std::array &abbrCodes) { using namespace decls_block; SmallVector witnessIDs; unsigned abbrCode = abbrCodes[DefaultWitnessTableLayout::Code]; for (auto member : proto->getMembers()) { if (auto *value = dyn_cast(member)) { auto witness = proto->getDefaultWitness(value); if (!witness) continue; DeclID requirementID = addDeclRef(value); DeclID witnessID = addDeclRef(witness.getDecl()); witnessIDs.push_back(requirementID); witnessIDs.push_back(witnessID); // FIXME: Substitutions } } DefaultWitnessTableLayout::emitRecord(Out, ScratchRecord, abbrCode, witnessIDs); } 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."); } 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::FileUnit: DC = cast(DC)->getParentModule(); LLVM_FALLTHROUGH; case DeclContextKind::Module: abbrCode = DeclTypeAbbrCodes[XRefLayout::Code]; XRefLayout::emitRecord(Out, ScratchRecord, abbrCode, addModuleRef(cast(DC)), pathLen); break; case DeclContextKind::GenericTypeDecl: { writeCrossReference(DC->getParent(), pathLen + 1); auto generic = cast(DC); 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, addModuleRef(DC->getParentModule()), 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->getKind()); 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->getModuleContext(), 1); abbrCode = DeclTypeAbbrCodes[XRefOperatorOrAccessorPathPieceLayout::Code]; auto nameID = addDeclBaseNameRef(op->getName()); auto fixity = getStableFixity(op->getKind()); XRefOperatorOrAccessorPathPieceLayout::emitRecord(Out, ScratchRecord, abbrCode, nameID, fixity); return; } if (auto prec = dyn_cast(D)) { writeCrossReference(prec->getModuleContext(), 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 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 #define DEF_VERIFY_ATTR(DECL)\ static void verifyAttrSerializable(const DECL ## Decl *D) {\ for (auto Attr : D->getAttrs()) {\ assert(Attr->canAppearOnDecl(D) && "attribute cannot appear on a " #DECL);\ }\ } DEF_VERIFY_ATTR(Func) DEF_VERIFY_ATTR(Extension) DEF_VERIFY_ATTR(PatternBinding) DEF_VERIFY_ATTR(Operator) DEF_VERIFY_ATTR(PrecedenceGroup) DEF_VERIFY_ATTR(TypeAlias) DEF_VERIFY_ATTR(Type) DEF_VERIFY_ATTR(Struct) DEF_VERIFY_ATTR(Enum) DEF_VERIFY_ATTR(Class) DEF_VERIFY_ATTR(Protocol) DEF_VERIFY_ATTR(Var) DEF_VERIFY_ATTR(Subscript) DEF_VERIFY_ATTR(Constructor) DEF_VERIFY_ATTR(Destructor) #undef DEF_VERIFY_ATTR #else static void verifyAttrSerializable(const Decl *D) {} #endif static inline unsigned getOptionalOrZero(const llvm::Optional &X) { if (X.hasValue()) return X.getValue(); return 0; } void Serializer::writeDeclAttribute(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 = DeclTypeAbbrCodes[CLASS##DeclAttrLayout::Code]; \ CLASS##DeclAttrLayout::emitRecord(Out, ScratchRecord, abbrCode, \ DA->isImplicit()); \ return; \ } #include "swift/AST/Attr.def" case DAK_SILGenName: { auto *theAttr = cast(DA); auto abbrCode = DeclTypeAbbrCodes[SILGenNameDeclAttrLayout::Code]; SILGenNameDeclAttrLayout::emitRecord(Out, ScratchRecord, abbrCode, theAttr->isImplicit(), theAttr->Name); return; } case DAK_CDecl: { auto *theAttr = cast(DA); auto abbrCode = DeclTypeAbbrCodes[CDeclDeclAttrLayout::Code]; CDeclDeclAttrLayout::emitRecord(Out, ScratchRecord, abbrCode, theAttr->isImplicit(), theAttr->Name); return; } case DAK_Alignment: { auto *theAlignment = cast(DA); auto abbrCode = DeclTypeAbbrCodes[AlignmentDeclAttrLayout::Code]; AlignmentDeclAttrLayout::emitRecord(Out, ScratchRecord, abbrCode, theAlignment->isImplicit(), theAlignment->getValue()); return; } case DAK_SwiftNativeObjCRuntimeBase: { auto *theBase = cast(DA); auto abbrCode = DeclTypeAbbrCodes[SwiftNativeObjCRuntimeBaseDeclAttrLayout::Code]; auto nameID = addDeclBaseNameRef(theBase->BaseClassName); SwiftNativeObjCRuntimeBaseDeclAttrLayout::emitRecord(Out, ScratchRecord, abbrCode, theBase->isImplicit(), nameID); return; } case DAK_Semantics: { auto *theAttr = cast(DA); auto abbrCode = DeclTypeAbbrCodes[SemanticsDeclAttrLayout::Code]; SemanticsDeclAttrLayout::emitRecord(Out, ScratchRecord, abbrCode, theAttr->isImplicit(), theAttr->Value); return; } case DAK_Inline: { auto *theAttr = cast(DA); auto abbrCode = DeclTypeAbbrCodes[InlineDeclAttrLayout::Code]; InlineDeclAttrLayout::emitRecord(Out, ScratchRecord, abbrCode, (unsigned)theAttr->getKind()); return; } case DAK_Optimize: { auto *theAttr = cast(DA); auto abbrCode = DeclTypeAbbrCodes[OptimizeDeclAttrLayout::Code]; OptimizeDeclAttrLayout::emitRecord(Out, ScratchRecord, abbrCode, (unsigned)theAttr->getMode()); return; } case DAK_Effects: { auto *theAttr = cast(DA); auto abbrCode = DeclTypeAbbrCodes[EffectsDeclAttrLayout::Code]; EffectsDeclAttrLayout::emitRecord(Out, ScratchRecord, abbrCode, (unsigned)theAttr->getKind()); return; } case DAK_Available: { #define LIST_VER_TUPLE_PIECES(X)\ X##_Major, X##_Minor, X##_Subminor, X##_HasMinor, X##_HasSubminor #define DEF_VER_TUPLE_PIECES(X, X_Expr)\ unsigned X##_Major = 0, X##_Minor = 0, X##_Subminor = 0,\ X##_HasMinor = 0, X##_HasSubminor = 0;\ const auto &X##_Val = X_Expr;\ if (X##_Val.hasValue()) {\ const auto &Y = X##_Val.getValue();\ X##_Major = Y.getMajor();\ X##_Minor = getOptionalOrZero(Y.getMinor());\ X##_Subminor = getOptionalOrZero(Y.getSubminor());\ X##_HasMinor = Y.getMinor().hasValue();\ X##_HasSubminor = Y.getSubminor().hasValue();\ } auto *theAttr = cast(DA); DEF_VER_TUPLE_PIECES(Introduced, theAttr->Introduced) DEF_VER_TUPLE_PIECES(Deprecated, theAttr->Deprecated) DEF_VER_TUPLE_PIECES(Obsoleted, theAttr->Obsoleted) llvm::SmallString<32> blob; blob.append(theAttr->Message); blob.append(theAttr->Rename); auto abbrCode = DeclTypeAbbrCodes[AvailableDeclAttrLayout::Code]; AvailableDeclAttrLayout::emitRecord( Out, 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; #undef LIST_VER_TUPLE_PIECES #undef DEF_VER_TUPLE_PIECES } 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(addDeclBaseNameRef(piece)); } } auto abbrCode = DeclTypeAbbrCodes[ObjCDeclAttrLayout::Code]; ObjCDeclAttrLayout::emitRecord(Out, ScratchRecord, abbrCode, theAttr->isImplicit(), theAttr->isSwift3Inferred(), theAttr->isNameImplicit(), numArgs, pieces); return; } case DAK_Specialize: { auto abbrCode = DeclTypeAbbrCodes[SpecializeDeclAttrLayout::Code]; auto SA = cast(DA); SpecializeDeclAttrLayout::emitRecord(Out, ScratchRecord, abbrCode, (unsigned)SA->isExported(), (unsigned)SA->getSpecializationKind()); writeGenericRequirements(SA->getRequirements(), DeclTypeAbbrCodes); return; } case DAK_DynamicReplacement: { auto abbrCode = DeclTypeAbbrCodes[DynamicReplacementDeclAttrLayout::Code]; auto theAttr = cast(DA); auto replacedFun = theAttr->getReplacedFunctionName(); SmallVector pieces; pieces.push_back(addDeclBaseNameRef(replacedFun.getBaseName())); for (auto argName : replacedFun.getArgumentNames()) pieces.push_back(addDeclBaseNameRef(argName)); assert(theAttr->getReplacedFunction()); DynamicReplacementDeclAttrLayout::emitRecord( Out, ScratchRecord, abbrCode, false, /*implicit flag*/ addDeclRef(theAttr->getReplacedFunction()), pieces.size(), pieces); return; } } } bool Serializer::isDeclXRef(const Decl *D) const { const DeclContext *topLevel = D->getDeclContext()->getModuleScopeContext(); if (topLevel->getParentModule() != M) return true; if (!SF || topLevel == SF) 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::writeDeclContext(const DeclContext *DC) { using namespace decls_block; auto isDecl = false; auto id = DeclContextIDs[DC]; assert(id != 0 && "decl context not referenced properly"); (void)id; assert((id - 1) == DeclContextOffsets.size()); DeclContextOffsets.push_back(Out.GetCurrentBitNo()); auto abbrCode = DeclTypeAbbrCodes[DeclContextLayout::Code]; DeclContextID declOrDeclContextID = 0; switch (DC->getContextKind()) { case DeclContextKind::AbstractFunctionDecl: case DeclContextKind::SubscriptDecl: case DeclContextKind::GenericTypeDecl: case DeclContextKind::ExtensionDecl: case DeclContextKind::EnumElementDecl: declOrDeclContextID = addDeclRef(getDeclForContext(DC)); isDecl = true; break; case DeclContextKind::TopLevelCodeDecl: case DeclContextKind::AbstractClosureExpr: case DeclContextKind::Initializer: case DeclContextKind::SerializedLocal: declOrDeclContextID = addLocalDeclContextRef(DC); break; case DeclContextKind::Module: llvm_unreachable("References to the module are serialized implicitly"); case DeclContextKind::FileUnit: llvm_unreachable("Can't serialize a FileUnit"); } DeclContextLayout::emitRecord(Out, ScratchRecord, abbrCode, declOrDeclContextID, isDecl); } void Serializer::writePatternBindingInitializer(PatternBindingDecl *binding, unsigned bindingIndex) { using namespace decls_block; auto abbrCode = DeclTypeAbbrCodes[PatternBindingInitializerLayout::Code]; StringRef initStr; SmallString<128> scratch; auto &entry = binding->getPatternList()[bindingIndex]; auto varDecl = entry.getAnchoringVarDecl(); if (entry.hasInitStringRepresentation() && varDecl->isInitExposedToClients()) { initStr = entry.getInitStringRepresentation(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]; DefaultArgumentInitializerLayout::emitRecord(Out, ScratchRecord, abbrCode, addDeclContextRef(parentContext), index); } void Serializer::writeAbstractClosureExpr(const DeclContext *parentContext, Type Ty, bool isImplicit, unsigned discriminator) { using namespace decls_block; auto abbrCode = DeclTypeAbbrCodes[AbstractClosureExprLayout::Code]; AbstractClosureExprLayout::emitRecord(Out, ScratchRecord, abbrCode, addTypeRef(Ty), isImplicit, discriminator, addDeclContextRef(parentContext)); } void Serializer::writeLocalDeclContext(const DeclContext *DC) { using namespace decls_block; assert(shouldSerializeAsLocalContext(DC) && "Can't serialize as local context"); auto id = LocalDeclContextIDs[DC]; assert(id != 0 && "decl context not referenced properly"); (void)id; assert((id - 1)== LocalDeclContextOffsets.size()); LocalDeclContextOffsets.push_back(Out.GetCurrentBitNo()); 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())); 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())); return; } } } default: llvm_unreachable("Trying to write a DeclContext that isn't local"); } } 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 getRawStableVarDeclSpecifier(swift::VarDecl::Specifier sf) { switch (sf) { case swift::VarDecl::Specifier::Let: return uint8_t(serialization::VarDeclSpecifier::Let); case swift::VarDecl::Specifier::Var: return uint8_t(serialization::VarDeclSpecifier::Var); case swift::VarDecl::Specifier::InOut: return uint8_t(serialization::VarDeclSpecifier::InOut); case swift::VarDecl::Specifier::Shared: return uint8_t(serialization::VarDeclSpecifier::Shared); case swift::VarDecl::Specifier::Owned: return uint8_t(serialization::VarDeclSpecifier::Owned); } llvm_unreachable("bad variable decl specifier kind"); } void Serializer::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 = addTypeRef(fec.getErrorParameterType()); TypeID resultTypeID; switch (fec.getKind()) { case ForeignErrorConvention::ZeroResult: case ForeignErrorConvention::NonZeroResult: resultTypeID = addTypeRef(fec.getResultType()); break; case ForeignErrorConvention::ZeroPreservedResult: case ForeignErrorConvention::NilResult: case ForeignErrorConvention::NonNilError: resultTypeID = 0; break; } auto abbrCode = DeclTypeAbbrCodes[ForeignErrorConventionLayout::Code]; ForeignErrorConventionLayout::emitRecord(Out, ScratchRecord, abbrCode, static_cast(kind), isOwned, isReplaced, fec.getErrorParameterIndex(), errorParameterTypeID, resultTypeID); } /// 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 ModuleDecl *problemModule) { return decl->getParentModule() == problemModule; } static void collectDependenciesFromType(llvm::SmallSetVector &seen, Type ty, const ModuleDecl *excluding) { ty.visit([&](Type next) { auto *nominal = next->getAnyNominal(); if (!nominal) return; // 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 if (contextDependsOn(nominal, excluding)) return; seen.insert(nominal->getDeclaredInterfaceType()); }); } static void collectDependenciesFromRequirement(llvm::SmallSetVector &seen, const Requirement &req, const ModuleDecl *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(); } void Serializer::writeDecl(const Decl *D) { using namespace decls_block; PrettyStackTraceDecl trace("serializing", D); auto id = DeclAndTypeIDs[D]; assert(id != 0 && "decl or type not referenced properly"); (void)id; assert((id - 1) == DeclOffsets.size()); assert((TypeOffsets.empty() || TypeOffsets.back() != Out.GetCurrentBitNo()) && "encoding Decl and Type to the same offset"); DeclOffsets.push_back(Out.GetCurrentBitNo()); SWIFT_DEFER { // This is important enough to leave on in Release builds. if (DeclOffsets.back() == Out.GetCurrentBitNo()) { llvm::PrettyStackTraceString message("failed to serialize anything"); abort(); } }; assert(!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"); // Emit attributes (if any). auto &Attrs = D->getAttrs(); if (Attrs.begin() != Attrs.end()) { for (auto Attr : Attrs) writeDeclAttribute(Attr); } if (auto *value = dyn_cast(D)) { auto *storage = dyn_cast(value); auto access = value->getFormalAccess(); // Emit the private descriminator 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 shouldEmitPrivateDescriminator = 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 = M->arePrivateImportsEnabled() && !value->getDeclContext()->isLocalContext() && (access <= swift::AccessLevel::FilePrivate || (storage && storage->getFormalAccess() >= swift::AccessLevel::Internal && storage->hasPrivateAccessor())); if (shouldEmitFilenameForPrivate || shouldEmitPrivateDescriminator) { auto topLevelContext = value->getDeclContext()->getModuleScopeContext(); if (auto *enclosingFile = dyn_cast(topLevelContext)) { if (shouldEmitPrivateDescriminator) { Identifier discriminator = enclosingFile->getDiscriminatorForPrivateValue(value); unsigned abbrCode = DeclTypeAbbrCodes[PrivateDiscriminatorLayout::Code]; PrivateDiscriminatorLayout::emitRecord( Out, ScratchRecord, abbrCode, 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 = addFilename(filename); FilenameForPrivateLayout::emitRecord( Out, ScratchRecord, DeclTypeAbbrCodes[FilenameForPrivateLayout::Code], filenameID); } } } } if (value->getDeclContext()->isLocalContext()) { auto discriminator = value->getLocalDiscriminator(); auto abbrCode = DeclTypeAbbrCodes[LocalDiscriminatorLayout::Code]; LocalDiscriminatorLayout::emitRecord(Out, ScratchRecord, abbrCode, discriminator); } } switch (D->getKind()) { case DeclKind::Import: llvm_unreachable("import decls should not be serialized"); case DeclKind::IfConfig: llvm_unreachable("#if block declarations should not be serialized"); case DeclKind::PoundDiagnostic: llvm_unreachable("#warning/#error declarations should not be serialized"); case DeclKind::Extension: { auto extension = cast(D); verifyAttrSerializable(extension); auto contextID = addDeclContextRef(extension->getDeclContext()); Type baseTy = extension->getExtendedType(); assert(!baseTy->hasUnboundGenericType()); assert(!baseTy->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. baseTy = baseTy->getCanonicalType(); // Make sure the base type has registered itself as a provider of generic // parameters. auto baseNominal = baseTy->getAnyNominal(); (void)addDeclRef(baseNominal); auto conformances = extension->getLocalConformances( ConformanceLookupKind::All, nullptr); SmallVector inheritedAndDependencyTypes; for (auto inherited : extension->getInherited()) { assert(!inherited.getType()->hasArchetype()); inheritedAndDependencyTypes.push_back(addTypeRef(inherited.getType())); } size_t numInherited = inheritedAndDependencyTypes.size(); llvm::SmallSetVector dependencies; collectDependenciesFromType(dependencies, baseTy, /*excluding*/nullptr); for (Requirement req : extension->getGenericRequirements()) { collectDependenciesFromRequirement(dependencies, req, /*excluding*/nullptr); } for (auto dependencyTy : dependencies) inheritedAndDependencyTypes.push_back(addTypeRef(dependencyTy)); unsigned abbrCode = DeclTypeAbbrCodes[ExtensionLayout::Code]; ExtensionLayout::emitRecord(Out, ScratchRecord, abbrCode, addTypeRef(baseTy), contextID, extension->isImplicit(), addGenericEnvironmentRef( extension->getGenericEnvironment()), conformances.size(), numInherited, inheritedAndDependencyTypes); bool isClassExtension = false; if (baseNominal) { isClassExtension = isa(baseNominal) || isa(baseNominal); } // 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. std::reverse(allGenericParams.begin(), allGenericParams.end()); for (auto *genericParams : allGenericParams) writeGenericParams(genericParams); writeMembers(id, extension->getMembers(), isClassExtension); writeConformances(conformances, DeclTypeAbbrCodes); break; } case DeclKind::EnumCase: llvm_unreachable("enum case decls should not be serialized"); case DeclKind::PatternBinding: { auto binding = cast(D); verifyAttrSerializable(binding); auto contextID = addDeclContextRef(binding->getDeclContext()); SmallVector initContextIDs; for (unsigned i : range(binding->getNumPatternEntries())) { auto initContextID = addDeclContextRef(binding->getPatternList()[i].getInitContext()); if (!initContextIDs.empty()) { initContextIDs.push_back(initContextID); } else if (initContextID) { initContextIDs.append(i, 0); initContextIDs.push_back(initContextID); } } unsigned abbrCode = DeclTypeAbbrCodes[PatternBindingLayout::Code]; PatternBindingLayout::emitRecord( Out, ScratchRecord, abbrCode, contextID, binding->isImplicit(), binding->isStatic(), uint8_t(getStableStaticSpelling(binding->getStaticSpelling())), binding->getNumPatternEntries(), initContextIDs); DeclContext *owningDC = nullptr; if (binding->getDeclContext()->isTypeContext()) owningDC = binding->getDeclContext(); for (auto entry : binding->getPatternList()) { writePattern(entry.getPattern(), owningDC); // Ignore initializer; external clients don't need to know about it. } break; } case DeclKind::TopLevelCode: // Top-level code is ignored; external clients don't need to know about it. break; case DeclKind::PrecedenceGroup: { auto group = cast(D); verifyAttrSerializable(group); auto contextID = addDeclContextRef(group->getDeclContext()); auto nameID = addDeclBaseNameRef(group->getName()); auto associativity = getRawStableAssociativity(group->getAssociativity()); SmallVector relations; for (auto &rel : group->getHigherThan()) relations.push_back(addDeclRef(rel.Group)); for (auto &rel : group->getLowerThan()) relations.push_back(addDeclRef(rel.Group)); unsigned abbrCode = DeclTypeAbbrCodes[PrecedenceGroupLayout::Code]; PrecedenceGroupLayout::emitRecord(Out, ScratchRecord, abbrCode, nameID, contextID, associativity, group->isAssignment(), group->getHigherThan().size(), relations); break; } case DeclKind::MissingMember: llvm_unreachable("member placeholders shouldn't be serialized"); case DeclKind::InfixOperator: { auto op = cast(D); verifyAttrSerializable(op); auto contextID = addDeclContextRef(op->getDeclContext()); auto nameID = addDeclBaseNameRef(op->getName()); auto groupID = addDeclRef(op->getPrecedenceGroup()); SmallVector designatedNominalTypeDeclIDs; for (auto *decl : op->getDesignatedNominalTypes()) designatedNominalTypeDeclIDs.push_back(addDeclRef(decl)); unsigned abbrCode = DeclTypeAbbrCodes[InfixOperatorLayout::Code]; InfixOperatorLayout::emitRecord(Out, ScratchRecord, abbrCode, nameID, contextID, groupID, designatedNominalTypeDeclIDs); break; } case DeclKind::PrefixOperator: { auto op = cast(D); verifyAttrSerializable(op); auto contextID = addDeclContextRef(op->getDeclContext()); SmallVector designatedNominalTypeDeclIDs; for (auto *decl : op->getDesignatedNominalTypes()) designatedNominalTypeDeclIDs.push_back(addDeclRef(decl)); unsigned abbrCode = DeclTypeAbbrCodes[PrefixOperatorLayout::Code]; PrefixOperatorLayout::emitRecord(Out, ScratchRecord, abbrCode, addDeclBaseNameRef(op->getName()), contextID, designatedNominalTypeDeclIDs); break; } case DeclKind::PostfixOperator: { auto op = cast(D); verifyAttrSerializable(op); auto contextID = addDeclContextRef(op->getDeclContext()); SmallVector designatedNominalTypeDeclIDs; for (auto *decl : op->getDesignatedNominalTypes()) designatedNominalTypeDeclIDs.push_back(addDeclRef(decl)); unsigned abbrCode = DeclTypeAbbrCodes[PostfixOperatorLayout::Code]; PostfixOperatorLayout::emitRecord(Out, ScratchRecord, abbrCode, addDeclBaseNameRef(op->getName()), contextID, designatedNominalTypeDeclIDs); break; } case DeclKind::TypeAlias: { auto typeAlias = cast(D); assert(!typeAlias->isObjC() && "ObjC typealias is not meaningful"); verifyAttrSerializable(typeAlias); auto contextID = addDeclContextRef(typeAlias->getDeclContext()); auto underlying = typeAlias->getUnderlyingTypeLoc().getType(); 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(addTypeRef(dep)); uint8_t rawAccessLevel = getRawStableAccessLevel(typeAlias->getFormalAccess()); unsigned abbrCode = DeclTypeAbbrCodes[TypeAliasLayout::Code]; TypeAliasLayout::emitRecord(Out, ScratchRecord, abbrCode, addDeclBaseNameRef(typeAlias->getName()), contextID, addTypeRef(underlying), /*no longer used*/TypeID(), typeAlias->isImplicit(), addGenericEnvironmentRef( typeAlias->getGenericEnvironment()), rawAccessLevel, dependencyIDs); writeGenericParams(typeAlias->getGenericParams()); break; } case DeclKind::GenericTypeParam: { auto genericParam = cast(D); verifyAttrSerializable(genericParam); unsigned abbrCode = DeclTypeAbbrCodes[GenericTypeParamDeclLayout::Code]; GenericTypeParamDeclLayout::emitRecord(Out, ScratchRecord, abbrCode, addDeclBaseNameRef(genericParam->getName()), genericParam->isImplicit(), genericParam->getDepth(), genericParam->getIndex()); break; } case DeclKind::AssociatedType: { auto assocType = cast(D); verifyAttrSerializable(assocType); auto contextID = addDeclContextRef(assocType->getDeclContext()); SmallVector overriddenAssocTypeIDs; for (auto overridden : assocType->getOverriddenDecls()) { overriddenAssocTypeIDs.push_back(addDeclRef(overridden)); } unsigned abbrCode = DeclTypeAbbrCodes[AssociatedTypeDeclLayout::Code]; AssociatedTypeDeclLayout::emitRecord( Out, ScratchRecord, abbrCode, addDeclBaseNameRef(assocType->getName()), contextID, addTypeRef(assocType->getDefaultDefinitionType()), assocType->isImplicit(), overriddenAssocTypeIDs); break; } case DeclKind::Struct: { auto theStruct = cast(D); verifyAttrSerializable(theStruct); auto contextID = addDeclContextRef(theStruct->getDeclContext()); auto conformances = theStruct->getLocalConformances( ConformanceLookupKind::All, nullptr); SmallVector inheritedTypes; for (auto inherited : theStruct->getInherited()) { assert(!inherited.getType()->hasArchetype()); inheritedTypes.push_back(addTypeRef(inherited.getType())); } uint8_t rawAccessLevel = getRawStableAccessLevel(theStruct->getFormalAccess()); unsigned abbrCode = DeclTypeAbbrCodes[StructLayout::Code]; StructLayout::emitRecord(Out, ScratchRecord, abbrCode, addDeclBaseNameRef(theStruct->getName()), contextID, theStruct->isImplicit(), theStruct->isObjC(), addGenericEnvironmentRef( theStruct->getGenericEnvironment()), rawAccessLevel, conformances.size(), inheritedTypes); writeGenericParams(theStruct->getGenericParams()); writeMembers(id, theStruct->getMembers(), false); writeConformances(conformances, DeclTypeAbbrCodes); break; } case DeclKind::Enum: { auto theEnum = cast(D); verifyAttrSerializable(theEnum); auto contextID = addDeclContextRef(theEnum->getDeclContext()); auto conformances = theEnum->getLocalConformances( ConformanceLookupKind::All, nullptr); SmallVector inheritedAndDependencyTypes; for (auto inherited : theEnum->getInherited()) { assert(!inherited.getType()->hasArchetype()); inheritedAndDependencyTypes.push_back(addTypeRef(inherited.getType())); } llvm::SmallSetVector dependencyTypes; for (const EnumElementDecl *nextElt : theEnum->getAllElements()) { if (!nextElt->hasAssociatedValues()) continue; collectDependenciesFromType(dependencyTypes, nextElt->getArgumentInterfaceType(), /*excluding*/theEnum->getParentModule()); } for (Requirement req : theEnum->getGenericRequirements()) { collectDependenciesFromRequirement(dependencyTypes, req, /*excluding*/nullptr); } for (Type ty : dependencyTypes) inheritedAndDependencyTypes.push_back(addTypeRef(ty)); uint8_t rawAccessLevel = getRawStableAccessLevel(theEnum->getFormalAccess()); unsigned abbrCode = DeclTypeAbbrCodes[EnumLayout::Code]; EnumLayout::emitRecord(Out, ScratchRecord, abbrCode, addDeclBaseNameRef(theEnum->getName()), contextID, theEnum->isImplicit(), theEnum->isObjC(), addGenericEnvironmentRef( theEnum->getGenericEnvironment()), addTypeRef(theEnum->getRawType()), rawAccessLevel, conformances.size(), theEnum->getInherited().size(), inheritedAndDependencyTypes); writeGenericParams(theEnum->getGenericParams()); writeMembers(id, theEnum->getMembers(), false); writeConformances(conformances, DeclTypeAbbrCodes); break; } case DeclKind::Class: { auto theClass = cast(D); verifyAttrSerializable(theClass); assert(!theClass->isForeign()); auto contextID = addDeclContextRef(theClass->getDeclContext()); auto conformances = theClass->getLocalConformances( ConformanceLookupKind::All, nullptr); SmallVector inheritedTypes; for (auto inherited : theClass->getInherited()) { assert(!inherited.getType()->hasArchetype()); inheritedTypes.push_back(addTypeRef(inherited.getType())); } uint8_t rawAccessLevel = getRawStableAccessLevel(theClass->getFormalAccess()); bool inheritsSuperclassInitializers = const_cast(theClass)-> inheritsSuperclassInitializers(nullptr); unsigned abbrCode = DeclTypeAbbrCodes[ClassLayout::Code]; ClassLayout::emitRecord(Out, ScratchRecord, abbrCode, addDeclBaseNameRef(theClass->getName()), contextID, theClass->isImplicit(), theClass->isObjC(), theClass->requiresStoredPropertyInits(), inheritsSuperclassInitializers, addGenericEnvironmentRef( theClass->getGenericEnvironment()), addTypeRef(theClass->getSuperclass()), rawAccessLevel, conformances.size(), inheritedTypes); writeGenericParams(theClass->getGenericParams()); writeMembers(id, theClass->getMembers(), true); writeConformances(conformances, DeclTypeAbbrCodes); break; } case DeclKind::Protocol: { auto proto = cast(D); verifyAttrSerializable(proto); auto contextID = addDeclContextRef(proto->getDeclContext()); SmallVector inherited; for (auto element : proto->getInherited()) { assert(!element.getType()->hasArchetype()); inherited.push_back(addTypeRef(element.getType())); } uint8_t rawAccessLevel = getRawStableAccessLevel(proto->getFormalAccess()); unsigned abbrCode = DeclTypeAbbrCodes[ProtocolLayout::Code]; ProtocolLayout::emitRecord(Out, ScratchRecord, abbrCode, addDeclBaseNameRef(proto->getName()), contextID, proto->isImplicit(), const_cast(proto) ->requiresClass(), proto->isObjC(), proto->existentialTypeSupported( /*resolver=*/nullptr), addGenericEnvironmentRef( proto->getGenericEnvironment()), addTypeRef(proto->getSuperclass()), rawAccessLevel, inherited); writeGenericParams(proto->getGenericParams()); writeGenericRequirements( proto->getRequirementSignature(), DeclTypeAbbrCodes); writeMembers(id, proto->getMembers(), true); writeDefaultWitnessTable(proto, DeclTypeAbbrCodes); break; } case DeclKind::Var: { auto var = cast(D); verifyAttrSerializable(var); auto contextID = 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()); Type ty = var->getInterfaceType(); SmallVector accessorsAndDependencies; for (auto accessor : accessors.Decls) accessorsAndDependencies.push_back(addDeclRef(accessor)); for (Type dependency : collectDependenciesFromType(ty->getCanonicalType())) accessorsAndDependencies.push_back(addTypeRef(dependency)); unsigned abbrCode = DeclTypeAbbrCodes[VarLayout::Code]; VarLayout::emitRecord(Out, ScratchRecord, abbrCode, addDeclBaseNameRef(var->getName()), contextID, var->isImplicit(), var->isObjC(), var->isStatic(), getRawStableVarDeclSpecifier(var->getSpecifier()), var->hasNonPatternBindingInit(), var->isGetterMutating(), var->isSetterMutating(), accessors.OpaqueReadOwnership, accessors.ReadImpl, accessors.WriteImpl, accessors.ReadWriteImpl, accessors.Decls.size(), addTypeRef(ty), addDeclRef(var->getOverriddenDecl()), rawAccessLevel, rawSetterAccessLevel, accessorsAndDependencies); break; } case DeclKind::Param: { auto param = cast(D); verifyAttrSerializable(param); auto contextID = addDeclContextRef(param->getDeclContext()); Type interfaceType = param->getInterfaceType(); // Only save the text for normal default arguments, not any of the special // ones. StringRef defaultArgumentText; SmallString<128> scratch; if (param->getDefaultArgumentKind() == swift::DefaultArgumentKind::Normal) defaultArgumentText = param->getDefaultValueStringRepresentation(scratch); unsigned abbrCode = DeclTypeAbbrCodes[ParamLayout::Code]; ParamLayout::emitRecord(Out, ScratchRecord, abbrCode, addDeclBaseNameRef(param->getArgumentName()), addDeclBaseNameRef(param->getName()), contextID, getRawStableVarDeclSpecifier(param->getSpecifier()), addTypeRef(interfaceType), param->isVariadic(), param->isAutoClosure(), getRawStableDefaultArgumentKind(param->getDefaultArgumentKind()), defaultArgumentText); if (interfaceType->hasError()) { param->getDeclContext()->dumpContext(); interfaceType->dump(); llvm_unreachable("error in interface type of parameter"); } break; } case DeclKind::Func: { auto fn = cast(D); verifyAttrSerializable(fn); auto contextID = addDeclContextRef(fn->getDeclContext()); unsigned abbrCode = DeclTypeAbbrCodes[FuncLayout::Code]; SmallVector nameComponentsAndDependencies; nameComponentsAndDependencies.push_back( addDeclBaseNameRef(fn->getFullName().getBaseName())); for (auto argName : fn->getFullName().getArgumentNames()) nameComponentsAndDependencies.push_back(addDeclBaseNameRef(argName)); uint8_t rawAccessLevel = getRawStableAccessLevel(fn->getFormalAccess()); uint8_t rawDefaultArgumentResilienceExpansion = getRawStableResilienceExpansion( fn->getDefaultArgumentResilienceExpansion()); Type ty = fn->getInterfaceType(); for (auto dependency : collectDependenciesFromType(ty->getCanonicalType())) nameComponentsAndDependencies.push_back(addTypeRef(dependency)); FuncLayout::emitRecord(Out, ScratchRecord, abbrCode, contextID, fn->isImplicit(), fn->isStatic(), uint8_t( getStableStaticSpelling(fn->getStaticSpelling())), fn->isObjC(), uint8_t( getStableSelfAccessKind(fn->getSelfAccessKind())), fn->hasDynamicSelf(), fn->hasForcedStaticDispatch(), fn->hasThrows(), addGenericEnvironmentRef( fn->getGenericEnvironment()), addTypeRef(fn->getResultInterfaceType()), addDeclRef(fn->getOperatorDecl()), addDeclRef(fn->getOverriddenDecl()), fn->getFullName().getArgumentNames().size() + fn->getFullName().isCompoundName(), rawAccessLevel, fn->needsNewVTableEntry(), rawDefaultArgumentResilienceExpansion, nameComponentsAndDependencies); writeGenericParams(fn->getGenericParams()); // Write the body parameters. writeParameterList(fn->getParameters()); if (auto errorConvention = fn->getForeignErrorConvention()) writeForeignErrorConvention(*errorConvention); writeInlinableBodyTextIfNeeded(fn); break; } case DeclKind::Accessor: { auto fn = cast(D); verifyAttrSerializable(fn); auto contextID = addDeclContextRef(fn->getDeclContext()); unsigned abbrCode = DeclTypeAbbrCodes[AccessorLayout::Code]; uint8_t rawAccessLevel = getRawStableAccessLevel(fn->getFormalAccess()); uint8_t rawAccessorKind = uint8_t(getStableAccessorKind(fn->getAccessorKind())); uint8_t rawDefaultArgumentResilienceExpansion = getRawStableResilienceExpansion( fn->getDefaultArgumentResilienceExpansion()); Type ty = fn->getInterfaceType(); SmallVector dependencies; for (auto dependency : collectDependenciesFromType(ty->getCanonicalType())) dependencies.push_back(addTypeRef(dependency)); AccessorLayout::emitRecord(Out, ScratchRecord, abbrCode, contextID, fn->isImplicit(), fn->isStatic(), uint8_t(getStableStaticSpelling( fn->getStaticSpelling())), fn->isObjC(), uint8_t(getStableSelfAccessKind( fn->getSelfAccessKind())), fn->hasDynamicSelf(), fn->hasForcedStaticDispatch(), fn->hasThrows(), addGenericEnvironmentRef( fn->getGenericEnvironment()), addTypeRef(fn->getResultInterfaceType()), addDeclRef(fn->getOverriddenDecl()), addDeclRef(fn->getStorage()), rawAccessorKind, rawAccessLevel, fn->needsNewVTableEntry(), rawDefaultArgumentResilienceExpansion, dependencies); writeGenericParams(fn->getGenericParams()); // Write the body parameters. writeParameterList(fn->getParameters()); if (auto errorConvention = fn->getForeignErrorConvention()) writeForeignErrorConvention(*errorConvention); writeInlinableBodyTextIfNeeded(fn); break; } case DeclKind::EnumElement: { auto elem = cast(D); auto contextID = addDeclContextRef(elem->getDeclContext()); SmallVector nameComponentsAndDependencies; nameComponentsAndDependencies.push_back(addDeclBaseNameRef(elem->getBaseName())); for (auto argName : elem->getFullName().getArgumentNames()) nameComponentsAndDependencies.push_back(addDeclBaseNameRef(argName)); Type ty = elem->getInterfaceType(); for (Type dependency : collectDependenciesFromType(ty->getCanonicalType())) nameComponentsAndDependencies.push_back(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 Negative = false; StringRef RawValueText; if (elem->getParentEnum()->isObjC()) { // Currently ObjC enums always have integer raw values. RawValueKind = EnumElementRawValueKind::IntegerLiteral; auto ILE = cast(elem->getRawValueExpr()); RawValueText = ILE->getDigitsText(); Negative = ILE->isNegative(); } uint8_t rawResilienceExpansion = getRawStableResilienceExpansion( elem->getDefaultArgumentResilienceExpansion()); unsigned abbrCode = DeclTypeAbbrCodes[EnumElementLayout::Code]; EnumElementLayout::emitRecord(Out, ScratchRecord, abbrCode, contextID, elem->isImplicit(), elem->hasAssociatedValues(), (unsigned)RawValueKind, Negative, addUniquedStringRef(RawValueText), rawResilienceExpansion, elem->getFullName().getArgumentNames().size()+1, nameComponentsAndDependencies); if (auto *PL = elem->getParameterList()) writeParameterList(PL); break; } case DeclKind::Subscript: { auto subscript = cast(D); verifyAttrSerializable(subscript); auto contextID = addDeclContextRef(subscript->getDeclContext()); Accessors accessors = getAccessors(subscript); SmallVector nameComponentsAndDependencies; for (auto argName : subscript->getFullName().getArgumentNames()) nameComponentsAndDependencies.push_back(addDeclBaseNameRef(argName)); for (auto accessor : accessors.Decls) nameComponentsAndDependencies.push_back(addDeclRef(accessor)); Type ty = subscript->getInterfaceType(); for (Type dependency : collectDependenciesFromType(ty->getCanonicalType())) nameComponentsAndDependencies.push_back(addTypeRef(dependency)); uint8_t rawAccessLevel = getRawStableAccessLevel(subscript->getFormalAccess()); uint8_t rawSetterAccessLevel = rawAccessLevel; if (subscript->isSettable()) rawSetterAccessLevel = getRawStableAccessLevel(subscript->getSetterFormalAccess()); unsigned abbrCode = DeclTypeAbbrCodes[SubscriptLayout::Code]; SubscriptLayout::emitRecord(Out, ScratchRecord, abbrCode, contextID, subscript->isImplicit(), subscript->isObjC(), subscript->isGetterMutating(), subscript->isSetterMutating(), accessors.OpaqueReadOwnership, accessors.ReadImpl, accessors.WriteImpl, accessors.ReadWriteImpl, accessors.Decls.size(), addGenericEnvironmentRef( subscript->getGenericEnvironment()), addTypeRef(subscript->getElementInterfaceType()), addDeclRef(subscript->getOverriddenDecl()), rawAccessLevel, rawSetterAccessLevel, subscript-> getFullName().getArgumentNames().size(), nameComponentsAndDependencies); writeGenericParams(subscript->getGenericParams()); writeParameterList(subscript->getIndices()); break; } case DeclKind::Constructor: { auto ctor = cast(D); verifyAttrSerializable(ctor); auto contextID = addDeclContextRef(ctor->getDeclContext()); SmallVector nameComponentsAndDependencies; for (auto argName : ctor->getFullName().getArgumentNames()) nameComponentsAndDependencies.push_back(addDeclBaseNameRef(argName)); Type ty = ctor->getInterfaceType(); for (Type dependency : collectDependenciesFromType(ty->getCanonicalType())) nameComponentsAndDependencies.push_back(addTypeRef(dependency)); uint8_t rawAccessLevel = getRawStableAccessLevel(ctor->getFormalAccess()); uint8_t rawDefaultArgumentResilienceExpansion = getRawStableResilienceExpansion( ctor->getDefaultArgumentResilienceExpansion()); bool firstTimeRequired = ctor->isRequired(); if (auto *overridden = ctor->getOverriddenDecl()) if (firstTimeRequired && overridden->isRequired()) firstTimeRequired = false; unsigned abbrCode = DeclTypeAbbrCodes[ConstructorLayout::Code]; ConstructorLayout::emitRecord(Out, ScratchRecord, abbrCode, contextID, getRawStableOptionalTypeKind( ctor->getFailability()), ctor->isImplicit(), ctor->isObjC(), ctor->hasStubImplementation(), ctor->hasThrows(), getStableCtorInitializerKind( ctor->getInitKind()), addGenericEnvironmentRef( ctor->getGenericEnvironment()), addDeclRef(ctor->getOverriddenDecl()), rawAccessLevel, ctor->needsNewVTableEntry(), rawDefaultArgumentResilienceExpansion, firstTimeRequired, ctor->getFullName().getArgumentNames().size(), nameComponentsAndDependencies); writeGenericParams(ctor->getGenericParams()); writeParameterList(ctor->getParameters()); if (auto errorConvention = ctor->getForeignErrorConvention()) writeForeignErrorConvention(*errorConvention); writeInlinableBodyTextIfNeeded(ctor); break; } case DeclKind::Destructor: { auto dtor = cast(D); verifyAttrSerializable(dtor); auto contextID = addDeclContextRef(dtor->getDeclContext()); unsigned abbrCode = DeclTypeAbbrCodes[DestructorLayout::Code]; DestructorLayout::emitRecord(Out, ScratchRecord, abbrCode, contextID, dtor->isImplicit(), dtor->isObjC(), addGenericEnvironmentRef( dtor->getGenericEnvironment())); writeInlinableBodyTextIfNeeded(dtor); break; } case DeclKind::Module: { llvm_unreachable("FIXME: serialize these"); } } } #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 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"); } #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(ModuleDecl::AccessPathTy(), Ctx.getIdentifier(TypeName), NLKind::QualifiedLookup, CurModuleResults); assert(CurModuleResults.size() == 1); return cast(CurModuleResults[0]); } void Serializer::writeType(Type ty) { using namespace decls_block; PrettyStackTraceType traceRAII(ty->getASTContext(), "serializing", ty); auto id = DeclAndTypeIDs[ty]; assert(id != 0 && "type not referenced properly"); (void)id; assert((id - 1) == TypeOffsets.size()); assert((DeclOffsets.empty() || DeclOffsets.back() != Out.GetCurrentBitNo()) && "encoding Decl and Type to the same offset"); TypeOffsets.push_back(Out.GetCurrentBitNo()); SWIFT_DEFER { // This is important enough to leave on in Release builds. if (TypeOffsets.back() == Out.GetCurrentBitNo()) { llvm::PrettyStackTraceString message("failed to serialize anything"); abort(); } }; switch (ty->getKind()) { case TypeKind::Error: case TypeKind::Unresolved: llvm_unreachable("should not serialize an invalid type"); case TypeKind::BuiltinInteger: case TypeKind::BuiltinIntegerLiteral: case TypeKind::BuiltinFloat: case TypeKind::BuiltinRawPointer: case TypeKind::BuiltinNativeObject: case TypeKind::BuiltinBridgeObject: case TypeKind::BuiltinUnknownObject: case TypeKind::BuiltinUnsafeValueBuffer: case TypeKind::BuiltinVector: case TypeKind::SILToken: { TypeAliasDecl *typeAlias = findTypeAliasForBuiltin(M->getASTContext(), ty); unsigned abbrCode = DeclTypeAbbrCodes[BuiltinAliasTypeLayout::Code]; BuiltinAliasTypeLayout::emitRecord(Out, ScratchRecord, abbrCode, addDeclRef(typeAlias, /*allowTypeAliasXRef*/true), TypeID()); break; } case TypeKind::TypeAlias: { auto alias = cast(ty.getPointer()); const TypeAliasDecl *typeAlias = alias->getDecl(); auto underlyingType = typeAlias->getUnderlyingTypeLoc().getType(); unsigned abbrCode = DeclTypeAbbrCodes[TypeAliasTypeLayout::Code]; TypeAliasTypeLayout::emitRecord( Out, ScratchRecord, abbrCode, addDeclRef(typeAlias, /*allowTypeAliasXRef*/true), addTypeRef(alias->getParent()), addTypeRef(underlyingType), addTypeRef(alias->getSinglyDesugaredType()), addSubstitutionMapRef(alias->getSubstitutionMap())); break; } case TypeKind::Paren: { auto parenTy = cast(ty.getPointer()); assert(parenTy->getParameterFlags().isNone()); unsigned abbrCode = DeclTypeAbbrCodes[ParenTypeLayout::Code]; ParenTypeLayout::emitRecord( Out, ScratchRecord, abbrCode, addTypeRef(parenTy->getUnderlyingType())); break; } case TypeKind::Tuple: { auto tupleTy = cast(ty.getPointer()); unsigned abbrCode = DeclTypeAbbrCodes[TupleTypeLayout::Code]; TupleTypeLayout::emitRecord(Out, ScratchRecord, abbrCode); abbrCode = DeclTypeAbbrCodes[TupleTypeEltLayout::Code]; for (auto &elt : tupleTy->getElements()) { assert(elt.getParameterFlags().isNone()); TupleTypeEltLayout::emitRecord( Out, ScratchRecord, abbrCode, addDeclBaseNameRef(elt.getName()), addTypeRef(elt.getType())); } break; } case TypeKind::Struct: case TypeKind::Enum: case TypeKind::Class: case TypeKind::Protocol: { auto nominalTy = cast(ty.getPointer()); unsigned abbrCode = DeclTypeAbbrCodes[NominalTypeLayout::Code]; NominalTypeLayout::emitRecord(Out, ScratchRecord, abbrCode, addDeclRef(nominalTy->getDecl()), addTypeRef(nominalTy->getParent())); break; } case TypeKind::ExistentialMetatype: { auto metatypeTy = cast(ty.getPointer()); unsigned abbrCode = DeclTypeAbbrCodes[ExistentialMetatypeTypeLayout::Code]; // Map the metatype representation. auto repr = getRawStableMetatypeRepresentation(metatypeTy); ExistentialMetatypeTypeLayout::emitRecord(Out, ScratchRecord, abbrCode, addTypeRef(metatypeTy->getInstanceType()), static_cast(repr)); break; } case TypeKind::Metatype: { auto metatypeTy = cast(ty.getPointer()); unsigned abbrCode = DeclTypeAbbrCodes[MetatypeTypeLayout::Code]; // Map the metatype representation. auto repr = getRawStableMetatypeRepresentation(metatypeTy); MetatypeTypeLayout::emitRecord(Out, ScratchRecord, abbrCode, addTypeRef(metatypeTy->getInstanceType()), static_cast(repr)); break; } case TypeKind::Module: llvm_unreachable("modules are currently not first-class values"); case TypeKind::DynamicSelf: { auto dynamicSelfTy = cast(ty.getPointer()); unsigned abbrCode = DeclTypeAbbrCodes[DynamicSelfTypeLayout::Code]; DynamicSelfTypeLayout::emitRecord(Out, ScratchRecord, abbrCode, addTypeRef(dynamicSelfTy->getSelfType())); break; } case TypeKind::PrimaryArchetype: { auto archetypeTy = cast(ty.getPointer()); auto env = archetypeTy->getGenericEnvironment(); GenericEnvironmentID envID = addGenericEnvironmentRef(env); auto interfaceType = archetypeTy->getInterfaceType() ->castTo(); unsigned abbrCode = DeclTypeAbbrCodes[PrimaryArchetypeTypeLayout::Code]; PrimaryArchetypeTypeLayout::emitRecord(Out, ScratchRecord, abbrCode, envID, interfaceType->getDepth(), interfaceType->getIndex()); break; } case TypeKind::OpenedArchetype: { auto archetypeTy = cast(ty.getPointer()); unsigned abbrCode = DeclTypeAbbrCodes[OpenedArchetypeTypeLayout::Code]; OpenedArchetypeTypeLayout::emitRecord(Out, ScratchRecord, abbrCode, addTypeRef(archetypeTy->getOpenedExistentialType())); break; } case TypeKind::NestedArchetype: { auto archetypeTy = cast(ty.getPointer()); auto rootTypeID = addTypeRef(archetypeTy->getRoot()); auto interfaceTypeID = addTypeRef(archetypeTy->getInterfaceType()); unsigned abbrCode = DeclTypeAbbrCodes[NestedArchetypeTypeLayout::Code]; NestedArchetypeTypeLayout::emitRecord(Out, ScratchRecord, abbrCode, rootTypeID, interfaceTypeID); break; } case TypeKind::GenericTypeParam: { auto genericParam = cast(ty.getPointer()); unsigned abbrCode = DeclTypeAbbrCodes[GenericTypeParamTypeLayout::Code]; DeclID declIDOrDepth; unsigned indexPlusOne; if (genericParam->getDecl() && !(genericParam->getDecl()->getDeclContext()->isModuleScopeContext() && isDeclXRef(genericParam->getDecl()))) { declIDOrDepth = addDeclRef(genericParam->getDecl()); indexPlusOne = 0; } else { declIDOrDepth = genericParam->getDepth(); indexPlusOne = genericParam->getIndex() + 1; } GenericTypeParamTypeLayout::emitRecord(Out, ScratchRecord, abbrCode, declIDOrDepth, indexPlusOne); break; } case TypeKind::DependentMember: { auto dependent = cast(ty.getPointer()); unsigned abbrCode = DeclTypeAbbrCodes[DependentMemberTypeLayout::Code]; assert(dependent->getAssocType() && "Unchecked dependent member type"); DependentMemberTypeLayout::emitRecord( Out, ScratchRecord, abbrCode, addTypeRef(dependent->getBase()), addDeclRef(dependent->getAssocType())); break; } case TypeKind::Function: case TypeKind::GenericFunction: { auto *fnTy = cast(ty.getPointer()); if (isa(fnTy)) { unsigned abbrCode = DeclTypeAbbrCodes[FunctionTypeLayout::Code]; FunctionTypeLayout::emitRecord(Out, ScratchRecord, abbrCode, addTypeRef(fnTy->getResult()), getRawStableFunctionTypeRepresentation(fnTy->getRepresentation()), fnTy->isNoEscape(), fnTy->throws()); } else { assert(!fnTy->isNoEscape()); auto *genericSig = cast(fnTy)->getGenericSignature(); unsigned abbrCode = DeclTypeAbbrCodes[GenericFunctionTypeLayout::Code]; GenericFunctionTypeLayout::emitRecord(Out, ScratchRecord, abbrCode, addTypeRef(fnTy->getResult()), getRawStableFunctionTypeRepresentation(fnTy->getRepresentation()), fnTy->throws(), addGenericSignatureRef(genericSig)); } unsigned abbrCode = DeclTypeAbbrCodes[FunctionParamLayout::Code]; for (auto ¶m : fnTy->getParams()) { auto paramFlags = param.getParameterFlags(); auto rawOwnership = getRawStableValueOwnership(paramFlags.getValueOwnership()); FunctionParamLayout::emitRecord( Out, ScratchRecord, abbrCode, addDeclBaseNameRef(param.getLabel()), addTypeRef(param.getPlainType()), paramFlags.isVariadic(), paramFlags.isAutoClosure(), paramFlags.isEscaping(), rawOwnership); } break; } case TypeKind::SILBlockStorage: { auto storageTy = cast(ty.getPointer()); unsigned abbrCode = DeclTypeAbbrCodes[SILBlockStorageTypeLayout::Code]; SILBlockStorageTypeLayout::emitRecord(Out, ScratchRecord, abbrCode, addTypeRef(storageTy->getCaptureType())); break; } case TypeKind::SILBox: { auto boxTy = cast(ty.getPointer()); unsigned abbrCode = DeclTypeAbbrCodes[SILBoxTypeLayout::Code]; SILLayoutID layoutRef = addSILLayoutRef(boxTy->getLayout()); SILBoxTypeLayout::emitRecord(Out, ScratchRecord, abbrCode, layoutRef, addSubstitutionMapRef(boxTy->getSubstitutions())); break; } case TypeKind::SILFunction: { auto fnTy = cast(ty.getPointer()); auto representation = fnTy->getRepresentation(); auto stableRepresentation = getRawStableSILFunctionTypeRepresentation(representation); SmallVector variableData; for (auto param : fnTy->getParameters()) { variableData.push_back(addTypeRef(param.getType())); unsigned conv = getRawStableParameterConvention(param.getConvention()); variableData.push_back(TypeID(conv)); } for (auto yield : fnTy->getYields()) { variableData.push_back(addTypeRef(yield.getType())); unsigned conv = getRawStableParameterConvention(yield.getConvention()); variableData.push_back(TypeID(conv)); } for (auto result : fnTy->getResults()) { variableData.push_back(addTypeRef(result.getType())); unsigned conv = getRawStableResultConvention(result.getConvention()); variableData.push_back(TypeID(conv)); } if (fnTy->hasErrorResult()) { auto abResult = fnTy->getErrorResult(); variableData.push_back(addTypeRef(abResult.getType())); unsigned conv = getRawStableResultConvention(abResult.getConvention()); variableData.push_back(TypeID(conv)); } auto sig = fnTy->getGenericSignature(); auto stableCoroutineKind = getRawStableSILCoroutineKind(fnTy->getCoroutineKind()); auto stableCalleeConvention = getRawStableParameterConvention(fnTy->getCalleeConvention()); unsigned abbrCode = DeclTypeAbbrCodes[SILFunctionTypeLayout::Code]; SILFunctionTypeLayout::emitRecord( Out, ScratchRecord, abbrCode, stableCoroutineKind, stableCalleeConvention, stableRepresentation, fnTy->isPseudogeneric(), fnTy->isNoEscape(), fnTy->hasErrorResult(), fnTy->getParameters().size(), fnTy->getNumYields(), fnTy->getNumResults(), addGenericSignatureRef(sig), variableData); if (auto conformance = fnTy->getWitnessMethodConformanceOrNone()) writeConformance(*conformance, DeclTypeAbbrCodes); break; } case TypeKind::ArraySlice: { auto sliceTy = cast(ty.getPointer()); Type base = sliceTy->getBaseType(); unsigned abbrCode = DeclTypeAbbrCodes[ArraySliceTypeLayout::Code]; ArraySliceTypeLayout::emitRecord(Out, ScratchRecord, abbrCode, addTypeRef(base)); break; } case TypeKind::Dictionary: { auto dictTy = cast(ty.getPointer()); unsigned abbrCode = DeclTypeAbbrCodes[DictionaryTypeLayout::Code]; DictionaryTypeLayout::emitRecord(Out, ScratchRecord, abbrCode, addTypeRef(dictTy->getKeyType()), addTypeRef(dictTy->getValueType())); break; } case TypeKind::Optional: { auto optionalTy = cast(ty.getPointer()); Type base = optionalTy->getBaseType(); unsigned abbrCode = DeclTypeAbbrCodes[OptionalTypeLayout::Code]; OptionalTypeLayout::emitRecord(Out, ScratchRecord, abbrCode, addTypeRef(base)); break; } case TypeKind::ProtocolComposition: { auto composition = cast(ty.getPointer()); SmallVector protocols; for (auto proto : composition->getMembers()) protocols.push_back(addTypeRef(proto)); unsigned abbrCode = DeclTypeAbbrCodes[ProtocolCompositionTypeLayout::Code]; ProtocolCompositionTypeLayout::emitRecord(Out, ScratchRecord, abbrCode, composition->hasExplicitAnyObject(), protocols); break; } #define REF_STORAGE(Name, ...) \ case TypeKind::Name##Storage: #include "swift/AST/ReferenceStorage.def" { auto refTy = cast(ty.getPointer()); unsigned abbrCode = DeclTypeAbbrCodes[ReferenceStorageTypeLayout::Code]; auto stableOwnership = getRawStableReferenceOwnership(refTy->getOwnership()); ReferenceStorageTypeLayout::emitRecord(Out, ScratchRecord, abbrCode, stableOwnership, addTypeRef(refTy->getReferentType())); break; } case TypeKind::UnboundGeneric: { auto generic = cast(ty.getPointer()); unsigned abbrCode = DeclTypeAbbrCodes[UnboundGenericTypeLayout::Code]; UnboundGenericTypeLayout::emitRecord(Out, ScratchRecord, abbrCode, addDeclRef(generic->getDecl(), /*allowTypeAliasXRef*/true), addTypeRef(generic->getParent())); break; } case TypeKind::BoundGenericClass: case TypeKind::BoundGenericEnum: case TypeKind::BoundGenericStruct: { auto generic = cast(ty.getPointer()); SmallVector genericArgIDs; for (auto next : generic->getGenericArgs()) genericArgIDs.push_back(addTypeRef(next)); unsigned abbrCode = DeclTypeAbbrCodes[BoundGenericTypeLayout::Code]; BoundGenericTypeLayout::emitRecord(Out, ScratchRecord, abbrCode, addDeclRef(generic->getDecl()), addTypeRef(generic->getParent()), genericArgIDs); break; } case TypeKind::InOut: llvm_unreachable("inout types are only used in function type parameters"); case TypeKind::LValue: llvm_unreachable("lvalue types are only used in function bodies"); case TypeKind::TypeVariable: llvm_unreachable("type variables should not escape the type checker"); } } 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(); #define DECL_ATTR(X, NAME, ...) \ registerDeclTypeAbbr(); #include "swift/AST/Attr.def" do { // Each of these loops can trigger the others to execute again, so repeat // until /all/ of the pending lists are empty. while (!DeclsAndTypesToWrite.empty()) { auto next = DeclsAndTypesToWrite.front(); DeclsAndTypesToWrite.pop(); if (next.isDecl()) writeDecl(next.getDecl()); else writeType(next.getType()); } while (!LocalDeclContextsToWrite.empty()) { auto next = LocalDeclContextsToWrite.front(); LocalDeclContextsToWrite.pop(); writeLocalDeclContext(next); } while (!DeclContextsToWrite.empty()) { auto next = DeclContextsToWrite.front(); DeclContextsToWrite.pop(); writeDeclContext(next); } while (!GenericSignaturesToWrite.empty()) { auto next = GenericSignaturesToWrite.front(); GenericSignaturesToWrite.pop(); writeGenericSignature(next); } while (!GenericEnvironmentsToWrite.empty()) { auto next = GenericEnvironmentsToWrite.front(); GenericEnvironmentsToWrite.pop(); writeGenericEnvironment(next); } while (!SubstitutionMapsToWrite.empty()) { auto next = SubstitutionMapsToWrite.front(); SubstitutionMapsToWrite.pop(); writeSubstitutionMap(next); } while (!NormalConformancesToWrite.empty()) { auto next = NormalConformancesToWrite.front(); NormalConformancesToWrite.pop(); writeNormalConformance(next); } while (!SILLayoutsToWrite.empty()) { auto next = SILLayoutsToWrite.front(); SILLayoutsToWrite.pop(); writeSILLayout(next); } } while (!DeclsAndTypesToWrite.empty() || !LocalDeclContextsToWrite.empty() || !DeclContextsToWrite.empty() || !SILLayoutsToWrite.empty() || !GenericSignaturesToWrite.empty() || !GenericEnvironmentsToWrite.empty() || !SubstitutionMapsToWrite.empty() || !NormalConformancesToWrite.empty()); } void Serializer::writeAllIdentifiers() { 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'); for (StringRef str : StringsToWrite) { IdentifierOffsets.push_back(stringData.size()); stringData.append(str); stringData.push_back('\0'); } IdentifierData.emit(ScratchRecord, stringData.str()); } void Serializer::writeOffsets(const index_block::OffsetsLayout &Offsets, const std::vector &values) { Offsets.emit(ScratchRecord, getOffsetRecordCode(values), values); } /// 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); } 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; // FIXME: DJB seed=0, audit whether the default seed could be used. return llvm::djbHash(key.getString(scratch), 0); } 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); } /// 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, bool isLocal = false) { const NominalTypeDecl *nominalParent = nullptr; for (const Decl *member : members) { // If there is a corresponding Objective-C method, record it. auto recordObjCMethod = [&] { if (isLocal) return; if (auto func = dyn_cast(member)) { if (func->isObjC()) { if (auto owningClass = func->getDeclContext()->getSelfClassDecl()) { 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()) { recordObjCMethod(); continue; } if (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) }); } } if (auto nestedType = dyn_cast(member)) { if (nestedType->getEffectiveAccess() > swift::AccessLevel::FilePrivate) { if (!nominalParent) { const DeclContext *DC = member->getDeclContext(); nominalParent = DC->getSelfNominalTypeDecl(); assert(nominalParent && "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->getMembers(), operatorMethodDecls, objcMethods, nestedTypeDecls, isLocal); } // Record Objective-C methods. recordObjCMethod(); } } void Serializer::writeAST(ModuleOrSourceFile DC, bool enableNestedTypeLookupTable) { DeclTable topLevelDecls, operatorDecls, operatorMethodDecls; DeclTable precedenceGroupDecls; ObjCMethodTable objcMethods; NestedTypeDeclsTable nestedTypeDecls; LocalTypeHashTableGenerator localTypeGenerator; ExtensionTable extensionDecls; bool hasLocalTypes = false; Optional entryPointClassID; SmallVector orderedTopLevelDecls; ArrayRef files; SmallVector Scratch; if (SF) { Scratch.push_back(SF); files = llvm::makeArrayRef(Scratch); } else { files = M->getFiles(); } for (auto nextFile : files) { if (nextFile->hasEntryPoint()) entryPointClassID = addDeclRef(nextFile->getMainClass()); // 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(); extensionDecls[extendedNominal->getName()] .push_back({ extendedNominal, addDeclRef(D) }); } else if (auto OD = dyn_cast(D)) { operatorDecls[OD->getName()] .push_back({ getStableFixity(OD->getKind()), 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"); } orderedTopLevelDecls.push_back(addDeclRef(D)); // If this is a global variable, force the accessors to be // serialized. if (auto VD = dyn_cast(D)) { if (VD->getGetter()) addDeclRef(VD->getGetter()); if (VD->getSetter()) addDeclRef(VD->getSetter()); } // 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)) { collectInterestingNestedDeclarations(*this, IDC->getMembers(), operatorMethodDecls, objcMethods, nestedTypeDecls); } } SmallVector localTypeDecls; nextFile->getLocalTypeDecls(localTypeDecls); for (auto TD : localTypeDecls) { 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)) { collectInterestingNestedDeclarations(*this, IDC->getMembers(), operatorMethodDecls, objcMethods, nestedTypeDecls, /*isLocal=*/true); } } } writeAllDeclsAndTypes(); writeAllIdentifiers(); { BCBlockRAII restoreBlock(Out, INDEX_BLOCK_ID, 4); index_block::OffsetsLayout Offsets(Out); writeOffsets(Offsets, DeclOffsets); writeOffsets(Offsets, TypeOffsets); writeOffsets(Offsets, IdentifierOffsets); writeOffsets(Offsets, DeclContextOffsets); writeOffsets(Offsets, LocalDeclContextOffsets); writeOffsets(Offsets, GenericSignatureOffsets); writeOffsets(Offsets, GenericEnvironmentOffsets); writeOffsets(Offsets, SubstitutionMapOffsets); writeOffsets(Offsets, NormalConformanceOffsets); writeOffsets(Offsets, SILLayoutOffsets); 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 (!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::ObjCMethodTableLayout ObjCMethodTable(Out); writeObjCMethodTable(ObjCMethodTable, objcMethods); if (enableNestedTypeLookupTable && !nestedTypeDecls.empty()) { index_block::NestedTypeDeclsLayout NestedTypeDeclsTable(Out); writeNestedTypeDeclsTable(NestedTypeDeclsTable, nestedTypeDecls); } 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) { 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, options.EnableNestedTypeLookupTable); } S.writeToStream(os); } void swift::serializeToBuffers( ModuleOrSourceFile DC, const SerializationOptions &options, std::unique_ptr *moduleBuffer, std::unique_ptr *moduleDocBuffer, const SILModule *M) { assert(options.OutputPath && options.OutputPath[0] != '\0'); { SharedTimer timer("Serialization, swiftmodule, to buffer"); llvm::SmallString<1024> buf; llvm::raw_svector_ostream stream(buf); Serializer::writeToStream(stream, DC, M, options); bool hadError = withOutputFile(getContext(DC).Diags, options.OutputPath, [&](raw_ostream &out) { out << stream.str(); return false; }); if (hadError) return; if (moduleBuffer) *moduleBuffer = llvm::make_unique( std::move(buf), options.OutputPath); } if (options.DocOutputPath && options.DocOutputPath[0] != '\0') { SharedTimer timer("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 = llvm::make_unique( std::move(buf), options.DocOutputPath); } } void swift::serialize(ModuleOrSourceFile DC, const SerializationOptions &options, const SILModule *M) { assert(options.OutputPath && options.OutputPath[0] != '\0'); if (strcmp("-", options.OutputPath) == 0) { // Special-case writing to stdout. Serializer::writeToStream(llvm::outs(), DC, M, options); assert(!options.DocOutputPath || options.DocOutputPath[0] == '\0'); return; } bool hadError = withOutputFile(getContext(DC).Diags, options.OutputPath, [&](raw_ostream &out) { SharedTimer timer("Serialization, swiftmodule"); Serializer::writeToStream(out, DC, M, options); return false; }); if (hadError) return; if (options.DocOutputPath && options.DocOutputPath[0] != '\0') { (void)withOutputFile(getContext(DC).Diags, options.DocOutputPath, [&](raw_ostream &out) { SharedTimer timer("Serialization, swiftdoc"); writeDocToStream(out, DC, options.GroupInfoPath); return false; }); } }