//===--- Serialization.cpp - Read and write Swift modules -----------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2017 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/ASTWalker.h" #include "swift/AST/DiagnosticsCommon.h" #include "swift/AST/Expr.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/USRGeneration.h" #include "swift/Basic/Dwarf.h" #include "swift/Basic/FileSystem.h" #include "swift/Basic/STLExtras.h" #include "swift/Basic/SourceManager.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 "clang/Basic/Module.h" // FIXME: We're just using CompilerInstance::createOutputFile. // This API should be sunk down to LLVM. #include "clang/Frontend/CompilerInstance.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/Compiler.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/YAMLParser.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; } namespace { /// Used to serialize the on-disk decl hash table. class DeclTableInfo { public: using key_type = Identifier; 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) { assert(!key.empty()); return llvm::HashString(key.str()); } std::pair EmitKeyDataLength(raw_ostream &out, key_type_ref key, data_type_ref data) { uint32_t keyLength = key.str().size(); uint32_t dataLength = (sizeof(uint32_t) + 1) * data.size(); endian::Writer writer(out); 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); for (auto entry : data) { writer.write(entry.first); writer.write(entry.second); } } }; class ExtensionTableInfo { serialization::Serializer &Serializer; llvm::SmallDenseMap MangledNameCache; public: explicit ExtensionTableInfo(serialization::Serializer &serializer) : Serializer(serializer) {} using key_type = Identifier; using key_type_ref = key_type; using data_type = Serializer::ExtensionTableData; using data_type_ref = const data_type &; using hash_value_type = uint32_t; using offset_type = unsigned; hash_value_type ComputeHash(key_type_ref key) { assert(!key.empty()); return llvm::HashString(key.str()); } 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(); uint32_t dataLength = (sizeof(uint32_t) * 2) * data.size(); for (auto dataPair : data) { int32_t nameData = getNameDataForBase(dataPair.first); if (nameData > 0) dataLength += nameData; } endian::Writer writer(out); 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); 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 = std::pair; // ID, local discriminator using data_type_ref = const data_type &; using hash_value_type = uint32_t; using offset_type = unsigned; hash_value_type ComputeHash(key_type_ref key) { assert(!key.empty()); return llvm::HashString(key); } std::pair EmitKeyDataLength(raw_ostream &out, key_type_ref key, data_type_ref data) { uint32_t keyLength = key.size(); uint32_t dataLength = sizeof(uint32_t) + sizeof(unsigned); endian::Writer writer(out); writer.write(keyLength); 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); writer.write(data.first); writer.write(data.second); } }; using LocalTypeHashTableGenerator = llvm::OnDiskChainedHashTableGenerator; class NestedTypeDeclsTableInfo { public: using key_type = Identifier; using key_type_ref = const key_type &; using data_type = Serializer::NestedTypeDeclsData; // (parent, child) pairs using data_type_ref = const data_type &; using hash_value_type = uint32_t; using offset_type = unsigned; hash_value_type ComputeHash(key_type_ref key) { assert(!key.empty()); return llvm::HashString(key.str()); } std::pair EmitKeyDataLength(raw_ostream &out, key_type_ref key, data_type_ref data) { uint32_t keyLength = key.str().size(); uint32_t dataLength = (sizeof(uint32_t) * 2) * data.size(); endian::Writer writer(out); 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); for (auto entry : data) { writer.write(entry.first); writer.write(entry.second); } } }; } // 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); } llvm_unreachable("Unhandled DeclContextKind in switch."); } namespace { struct Accessors { StorageKind Kind; FuncDecl *Get = nullptr, *Set = nullptr, *MaterializeForSet = nullptr; FuncDecl *Address = nullptr, *MutableAddress = nullptr; FuncDecl *WillSet = nullptr, *DidSet = nullptr; }; } // end anonymous namespace static StorageKind getRawStorageKind(AbstractStorageDecl::StorageKindTy kind) { switch (kind) { #define CASE(KIND) case AbstractStorageDecl::KIND: return StorageKind::KIND CASE(Stored); CASE(StoredWithTrivialAccessors); CASE(StoredWithObservers); CASE(InheritedWithObservers); CASE(Computed); CASE(ComputedWithMutableAddress); CASE(Addressed); CASE(AddressedWithTrivialAccessors); CASE(AddressedWithObservers); #undef CASE } llvm_unreachable("bad storage kind"); } static Accessors getAccessors(const AbstractStorageDecl *storage) { Accessors accessors; accessors.Kind = getRawStorageKind(storage->getStorageKind()); switch (auto storageKind = storage->getStorageKind()) { case AbstractStorageDecl::Stored: return accessors; case AbstractStorageDecl::Addressed: case AbstractStorageDecl::AddressedWithTrivialAccessors: case AbstractStorageDecl::ComputedWithMutableAddress: accessors.Address = storage->getAddressor(); accessors.MutableAddress = storage->getMutableAddressor(); if (storageKind == AbstractStorageDecl::Addressed) return accessors; goto getset; case AbstractStorageDecl::StoredWithObservers: case AbstractStorageDecl::InheritedWithObservers: case AbstractStorageDecl::AddressedWithObservers: accessors.WillSet = storage->getWillSetFunc(); accessors.DidSet = storage->getDidSetFunc(); goto getset; case AbstractStorageDecl::StoredWithTrivialAccessors: case AbstractStorageDecl::Computed: getset: accessors.Get = storage->getGetter(); accessors.Set = storage->getSetter(); accessors.MaterializeForSet = storage->getMaterializeForSetFunc(); return accessors; } llvm_unreachable("bad storage kind"); } 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; } 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; } 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 forceSerialization, bool allowTypeAliasXRef) { if (!D) return 0; DeclIDAndForce &id = DeclAndTypeIDs[D]; if (id.first != 0) { if (forceSerialization && !id.second) id.second = true; return id.first; } assert((!isDeclXRef(D) || isa(D) || isa(D) || isa(D)) && "cannot cross-reference this decl"); assert((allowTypeAliasXRef || !isa(D) || D->getModuleContext() == M) && "cannot cross-reference typealiases directly (use the NameAliasType)"); id = { ++LastDeclID, forceSerialization }; DeclsAndTypesToWrite.push(D); return id.first; } 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.first != 0) return id.first; id = { ++LastTypeID, true }; DeclsAndTypesToWrite.push(ty); return id.first; } IdentifierID Serializer::addIdentifierRef(Identifier ident) { if (ident.empty()) return 0; IdentifierID &id = IdentifierIDs[ident]; if (id != 0) return id; id = ++LastIdentifierID; IdentifiersToWrite.push_back(ident); return id; } 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; assert(!M->getName().empty()); return addIdentifierRef(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. static void emitBlockID(llvm::BitstreamWriter &out, 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); } /// Record the name of a record within a block. static void emitRecordID(llvm::BitstreamWriter &out, 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(Out, X ## _ID, #X, nameBuffer) #define BLOCK_RECORD(K, X) emitRecordID(Out, 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, 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(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); 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_ENVIRONMENT_OFFSETS); BLOCK_RECORD(index_block, DECL_CONTEXT_OFFSETS); BLOCK_RECORD(index_block, LOCAL_TYPE_DECLS); BLOCK_RECORD(index_block, GENERIC_ENVIRONMENT_OFFSETS); 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(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_DEFAULT_WITNESS_TABLE); BLOCK_RECORD(sil_block, SIL_DEFAULT_WITNESS_TABLE_ENTRY); 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); // These layouts can exist in both decl blocks and sil blocks. #define BLOCK_RECORD_WITH_NAMESPACE(K, X) emitRecordID(Out, X, #X, nameBuffer) BLOCK_RECORD_WITH_NAMESPACE(sil_block, decls_block::BOUND_GENERIC_SUBSTITUTION); 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::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_PARAM); 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); #undef BLOCK #undef BLOCK_RECORD } void Serializer::writeDocBlockInfoBlock() { BCBlockRAII restoreBlock(Out, llvm::bitc::BLOCKINFO_BLOCK_ID, 2); SmallVector nameBuffer; #define BLOCK(X) emitBlockID(Out, X ## _ID, #X, nameBuffer) #define BLOCK_RECORD(K, X) emitRecordID(Out, K::X, #X, nameBuffer) BLOCK(MODULE_DOC_BLOCK); BLOCK(CONTROL_BLOCK); BLOCK_RECORD(control_block, METADATA); BLOCK_RECORD(control_block, MODULE_NAME); BLOCK_RECORD(control_block, TARGET); BLOCK(COMMENT_BLOCK); BLOCK_RECORD(comment_block, DECL_COMMENTS); BLOCK_RECORD(comment_block, GROUP_NAMES); #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, VERSION_MAJOR, VERSION_MINOR, shortVersionStringLength, compatibilityVersionStringLength, versionString.str()); Target.emit(ScratchRecord, M->getASTContext().LangOpts.Target.str()); { llvm::BCBlockRAII restoreBlock(Out, OPTIONS_BLOCK_ID, 3); options_block::IsSIBLayout IsSIB(Out); IsSIB.emit(ScratchRecord, options.IsSIB); if (M->isTestingEnabled()) { options_block::IsTestableLayout IsTestable(Out); IsTestable.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); } } } } } void Serializer::writeDocHeader() { { BCBlockRAII restoreBlock(Out, CONTROL_BLOCK_ID, 3); control_block::ModuleNameLayout ModuleName(Out); control_block::MetadataLayout Metadata(Out); control_block::TargetLayout Target(Out); auto& LangOpts = M->getASTContext().LangOpts; Metadata.emit(ScratchRecord, VERSION_MAJOR, VERSION_MINOR, /*short version string length*/0, /*compatibility length*/0, version::getSwiftFullVersion( LangOpts.EffectiveLanguageVersion)); Target.emit(ScratchRecord, LangOpts.Target.str()); } } static void removeDuplicateImports(SmallVectorImpl &imports) { std::sort(imports.begin(), imports.end(), [](const ModuleDecl::ImportedModule &lhs, const ModuleDecl::ImportedModule &rhs) -> bool { // Arbitrarily sort by name to get a deterministic order. // FIXME: Submodules don't get sorted properly here. if (lhs.second != rhs.second) return lhs.second->getName().str() < rhs.second->getName().str(); using AccessPathElem = std::pair; return std::lexicographical_compare(lhs.first.begin(), lhs.first.end(), rhs.first.begin(), rhs.first.end(), [](const AccessPathElem &lElem, const AccessPathElem &rElem) { return lElem.first.str() < rElem.first.str(); }); }); auto last = std::unique(imports.begin(), imports.end(), [](const ModuleDecl::ImportedModule &lhs, const ModuleDecl::ImportedModule &rhs) -> bool { if (lhs.second != rhs.second) return false; return ModuleDecl::isSameAccessPath(lhs.first, rhs.first); }); imports.erase(last, imports.end()); } using ImportPathBlob = llvm::SmallString<64>; static void flattenImportPath(const ModuleDecl::ImportedModule &import, ImportPathBlob &out) { ArrayRef files = import.second->getFiles(); if (auto clangModule = dyn_cast(files.front())) { // FIXME: This is an awful hack to handle Clang submodules. // Once Swift has a native notion of submodules, this can go away. const clang::Module *submodule = clangModule->getClangModule(); SmallVector submoduleNames; do { submoduleNames.push_back(submodule->Name); submodule = submodule->Parent; } while (submodule); interleave(submoduleNames.rbegin(), submoduleNames.rend(), [&out](StringRef next) { out.append(next); }, [&out] { out.push_back('\0'); }); } else { out.append(import.second->getName().str()); } 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()); } 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::ModuleFlagsLayout ModuleFlags(Out); input_block::SearchPathLayout SearchPath(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); } // FIXME: Having to deal with private imports as a superset of public imports // is inefficient. SmallVector publicImports; SmallVector allImports; for (auto file : M->getFiles()) { file->getImportedModules(publicImports, ModuleDecl::ImportFilter::Public); file->getImportedModules(allImports, ModuleDecl::ImportFilter::All); } llvm::SmallSet publicImportSet; publicImportSet.insert(publicImports.begin(), publicImports.end()); removeDuplicateImports(allImports); auto clangImporter = static_cast(M->getASTContext().getClangModuleLoader()); ModuleDecl *importedHeaderModule = clangImporter->getImportedHeaderModule(); ModuleDecl *theBuiltinModule = M->getASTContext().TheBuiltinModule; for (auto import : allImports) { if (import.second == theBuiltinModule) continue; if (import.second == importedHeaderModule) { off_t importedHeaderSize = 0; time_t importedHeaderModTime = 0; std::string contents; if (!options.ImportedHeader.empty()) contents = clangImporter->getBridgingHeaderContents( options.ImportedHeader, importedHeaderSize, importedHeaderModTime); ImportedHeader.emit(ScratchRecord, publicImportSet.count(import), importedHeaderSize, importedHeaderModTime, options.ImportedHeader); if (!contents.empty()) { contents.push_back('\0'); ImportedHeaderContents.emit(ScratchRecord, contents); } 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(Nil) 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 getRawStableAddressorKind(swift::AddressorKind kind) { switch (kind) { case swift::AddressorKind::NotAddressor: return uint8_t(serialization::AddressorKind::NotAddressor); case swift::AddressorKind::Unsafe: return uint8_t(serialization::AddressorKind::Unsafe); case swift::AddressorKind::Owning: return uint8_t(serialization::AddressorKind::Owning); case swift::AddressorKind::NativeOwning: return uint8_t(serialization::AddressorKind::NativeOwning); case swift::AddressorKind::NativePinning: return uint8_t(serialization::AddressorKind::NativePinning); } llvm_unreachable("bad addressor kind"); } void Serializer::writeParameterList(const ParameterList *PL) { using namespace decls_block; unsigned abbrCode = DeclTypeAbbrCodes[ParameterListLayout::Code]; ParameterListLayout::emitRecord(Out, ScratchRecord, abbrCode, PL->size()); abbrCode = DeclTypeAbbrCodes[ParameterListEltLayout::Code]; for (auto ¶m : *PL) { // FIXME: Default argument expressions? auto defaultArg = getRawStableDefaultArgumentKind(param->getDefaultArgumentKind()); ParameterListEltLayout::emitRecord(Out, ScratchRecord, abbrCode, addDeclRef(param), param->isVariadic(), defaultArg); } } 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 = owningDC->getGenericEnvironmentOfContext() ->mapTypeOutOfContext(type); } 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, addIdentifierRef(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->getAlignment(); } 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); } } } bool Serializer::writeGenericParams(const GenericParamList *genericParams) { using namespace decls_block; // Don't write anything if there are no generic params. if (!genericParams) return true; unsigned abbrCode = DeclTypeAbbrCodes[GenericParamListLayout::Code]; GenericParamListLayout::emitRecord(Out, ScratchRecord, abbrCode); abbrCode = DeclTypeAbbrCodes[GenericParamLayout::Code]; for (auto next : genericParams->getParams()) { GenericParamLayout::emitRecord(Out, ScratchRecord, abbrCode, addDeclRef(next)); } return true; } 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()); GenericEnvironmentOffsets.push_back(Out.GetCurrentBitNo()); if (env == nullptr) return; // 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; } } } // 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 (SILMode) { if (decl) rawParamIDs.push_back(addIdentifierRef(decl->getName())); else rawParamIDs.push_back(addIdentifierRef(Identifier())); paramTy = paramTy->getCanonicalType()->castTo(); } rawParamIDs.push_back(addTypeRef(paramTy)); } if (SILMode) { auto envAbbrCode = DeclTypeAbbrCodes[SILGenericEnvironmentLayout::Code]; SILGenericEnvironmentLayout::emitRecord(Out, ScratchRecord, envAbbrCode, rawParamIDs); } else { auto envAbbrCode = DeclTypeAbbrCodes[GenericEnvironmentLayout::Code]; GenericEnvironmentLayout::emitRecord(Out, ScratchRecord, envAbbrCode, rawParamIDs); } writeGenericRequirements(env->getGenericSignature()->getRequirements(), 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); } // Save generic params. if (auto sig = layout->getGenericSignature()) { for (auto param : sig->getGenericParams()) { data.push_back(addTypeRef(param)); } } unsigned abbrCode = DeclTypeAbbrCodes[SILLayoutLayout::Code]; SILLayoutLayout::emitRecord(Out, ScratchRecord, abbrCode, layout->getFields().size(), data); // Emit requirements. if (auto sig = layout->getGenericSignature()) writeGenericRequirements(sig->getRequirements(), DeclTypeAbbrCodes); } 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->forEachValueWitness(nullptr, [&](ValueDecl *req, Witness witness) { 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; if (auto genericEnv = witness.requiresSubstitution() ? witness.getSyntheticEnvironment() : nullptr) { auto *genericSig = genericEnv->getGenericSignature(); // Generic parameters. data.push_back(genericSig->getGenericParams().size()); for (auto gp : genericSig->getGenericParams()) data.push_back(addTypeRef(gp)); auto reqToSyntheticSubs = witness.getRequirementToSyntheticSubs(); data.push_back(reqToSyntheticSubs.size()); // Requirements come at the end. } else { data.push_back(0); } data.push_back(witness.getSubstitutions().size()); ++numValueWitnesses; }); 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, /*forceSerialization*/false, /*allowTypeAliasXRef*/true)); ++numTypeWitnesses; return false; }); unsigned abbrCode = DeclTypeAbbrCodes[NormalProtocolConformanceLayout::Code]; auto ownerID = addDeclContextRef(conformance->getDeclContext()); NormalProtocolConformanceLayout::emitRecord(Out, ScratchRecord, abbrCode, addDeclRef(protocol), ownerID, numValueWitnesses, numTypeWitnesses, data); // Write requirement signature conformances. for (auto reqConformance : conformance->getSignatureConformances()) writeConformance(reqConformance, DeclTypeAbbrCodes); conformance->forEachValueWitness(nullptr, [&](ValueDecl *req, Witness witness) { // Bail out early for simple witnesses. if (!witness.getDecl()) return; if (auto genericEnv = witness.requiresSubstitution() ? witness.getSyntheticEnvironment() : nullptr) { auto *genericSig = genericEnv->getGenericSignature(); // Write the generic requirements of the synthetic environment. writeGenericRequirements(genericSig->getRequirements(), DeclTypeAbbrCodes); // Write requirement-to-synthetic substitutions. writeSubstitutions(witness.getRequirementToSyntheticSubs(), DeclTypeAbbrCodes, nullptr); } // Write the witness substitutions. writeSubstitutions(witness.getSubstitutions(), DeclTypeAbbrCodes, witness.requiresSubstitution() ? witness.getSyntheticEnvironment() : nullptr); }); } 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.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()))) { // 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::Specialized: { auto conf = cast(conformance); auto substitutions = conf->getGenericSubstitutions(); unsigned abbrCode = abbrCodes[SpecializedProtocolConformanceLayout::Code]; auto type = conf->getType(); if (genericEnv && type->hasArchetype()) type = genericEnv->mapTypeOutOfContext(type); SpecializedProtocolConformanceLayout::emitRecord(Out, ScratchRecord, abbrCode, addTypeRef(type), substitutions.size()); writeSubstitutions(substitutions, abbrCodes, genericEnv); 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 = genericEnv->mapTypeOutOfContext(type); 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); } void Serializer::writeSubstitutions(SubstitutionList substitutions, const std::array &abbrCodes, GenericEnvironment *genericEnv) { using namespace decls_block; auto abbrCode = abbrCodes[BoundGenericSubstitutionLayout::Code]; for (auto &sub : substitutions) { auto replacementType = sub.getReplacement(); if (genericEnv && replacementType->hasArchetype()) { replacementType = genericEnv->mapTypeOutOfContext(replacementType); } BoundGenericSubstitutionLayout::emitRecord( Out, ScratchRecord, abbrCode, addTypeRef(replacementType), sub.getConformances().size()); for (auto conformance : sub.getConformances()) { writeConformance(conformance, abbrCodes, genericEnv); } } } 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::IfConfig: 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: return true; } llvm_unreachable("Unhandled DeclKind in switch."); } void Serializer::writeMembers(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 (isClass) { if (auto VD = dyn_cast(member)) { if (VD->canBeAccessedByDynamicLookup()) { auto &list = ClassMembersByName[VD->getName()]; 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)) { ConcreteDeclRef 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) { case swift::AccessorKind::NotAccessor: llvm_unreachable("should only be called for actual accessors"); #define CASE(NAME) \ case swift::AccessorKind::Is##NAME: return serialization::NAME; CASE(Getter) CASE(Setter) CASE(WillSet) CASE(DidSet) CASE(MaterializeForSet) CASE(Addressor) CASE(MutableAddressor) #undef CASE } 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: 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]; XRefTypePathPieceLayout::emitRecord(Out, ScratchRecord, abbrCode, addIdentifierRef(generic->getName()), false); break; } case DeclContextKind::ExtensionDecl: { auto ext = cast(DC); Type baseTy = ext->getExtendedType(); writeCrossReference(baseTy->getAnyNominal(), pathLen + 1); abbrCode = DeclTypeAbbrCodes[XRefExtensionPathPieceLayout::Code]; SmallVector genericParams; CanGenericSignature genericSig(nullptr); if (ext->isConstrainedExtension()) { genericSig = ext->getGenericSignature()->getCanonicalSignature(); for (auto param : genericSig->getGenericParams()) genericParams.push_back(addTypeRef(param)); } XRefExtensionPathPieceLayout::emitRecord( Out, ScratchRecord, abbrCode, addModuleRef(DC->getParentModule()), genericParams); if (genericSig) { writeGenericRequirements(genericSig->getRequirements(), DeclTypeAbbrCodes); } 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()->getAsProtocolExtensionContext(); XRefValuePathPieceLayout::emitRecord(Out, ScratchRecord, abbrCode, addTypeRef(ty), addIdentifierRef(SD->getName()), isProtocolExt, SD->isStatic()); break; } case DeclContextKind::AbstractFunctionDecl: { if (auto fn = dyn_cast(DC)) { if (auto storage = fn->getAccessorStorageDecl()) { writeCrossReference(storage->getDeclContext(), pathLen + 2); Type ty = storage->getInterfaceType()->getCanonicalType(); auto nameID = addIdentifierRef(storage->getName()); bool isProtocolExt = fn->getDeclContext()->getAsProtocolExtensionContext(); abbrCode = DeclTypeAbbrCodes[XRefValuePathPieceLayout::Code]; XRefValuePathPieceLayout::emitRecord(Out, ScratchRecord, abbrCode, addTypeRef(ty), nameID, isProtocolExt, storage->isStatic()); abbrCode = DeclTypeAbbrCodes[XRefOperatorOrAccessorPathPieceLayout::Code]; auto emptyID = addIdentifierRef(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()->getAsProtocolExtensionContext(), getStableCtorInitializerKind(ctor->getInitKind())); break; } abbrCode = DeclTypeAbbrCodes[XRefValuePathPieceLayout::Code]; bool isProtocolExt = fn->getDeclContext()->getAsProtocolExtensionContext(); XRefValuePathPieceLayout::emitRecord(Out, ScratchRecord, abbrCode, addTypeRef(ty), addIdentifierRef(fn->getName()), isProtocolExt, 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 = addIdentifierRef(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 = addIdentifierRef(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 = addIdentifierRef(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->getIndex()); return; } bool isProtocolExt = D->getDeclContext()->getAsProtocolExtensionContext(); if (auto type = dyn_cast(D)) { abbrCode = DeclTypeAbbrCodes[XRefTypePathPieceLayout::Code]; XRefTypePathPieceLayout::emitRecord(Out, ScratchRecord, abbrCode, addIdentifierRef(type->getName()), isProtocolExt); return; } auto val = cast(D); auto ty = val->getInterfaceType()->getCanonicalType(); abbrCode = DeclTypeAbbrCodes[XRefValuePathPieceLayout::Code]; XRefValuePathPieceLayout::emitRecord(Out, ScratchRecord, abbrCode, addTypeRef(ty), addIdentifierRef(val->getName()), isProtocolExt, 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 getRawStableAccessibility(Accessibility access) { switch (access) { #define CASE(NAME) \ case Accessibility::NAME: \ return static_cast(serialization::AccessibilityKind::NAME); CASE(Private) CASE(FilePrivate) CASE(Internal) CASE(Public) CASE(Open) #undef CASE } llvm_unreachable("Unhandled AccessibilityKind 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 bool isForced(const Decl *D, const llvm::DenseMap &table) { if (table.lookup(D).second) return true; for (const DeclContext *DC = D->getDeclContext(); !DC->isModuleScopeContext(); DC = DC->getParent()) if (table.lookup(getDeclForContext(DC)).second) return true; return false; } 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; switch (DA->getKind()) { case DAK_RawDocComment: case DAK_Ownership: // Serialized as part of the type. case DAK_Accessibility: case DAK_SetterAccessibility: case DAK_ObjCBridged: case DAK_SynthesizedProtocol: case DAK_Count: case DAK_Implements: llvm_unreachable("cannot serialize attribute"); return; #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->Value); return; } case DAK_SwiftNativeObjCRuntimeBase: { auto *theBase = cast(DA); auto abbrCode = DeclTypeAbbrCodes[SwiftNativeObjCRuntimeBaseDeclAttrLayout::Code]; auto nameID = addIdentifierRef(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_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(), 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_AutoClosure: { auto *theAttr = cast(DA); auto abbrCode = DeclTypeAbbrCodes[AutoClosureDeclAttrLayout::Code]; AutoClosureDeclAttrLayout::emitRecord(Out, ScratchRecord, abbrCode, theAttr->isImplicit(), theAttr->isEscaping()); return; } case DAK_ObjC: { auto *theAttr = cast(DA); SmallVector pieces; unsigned numArgs = 0; if (auto name = theAttr->getName()) { numArgs = name->getNumArgs() + 1; for (auto piece : name->getSelectorPieces()) { pieces.push_back(addIdentifierRef(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; } } } 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 !isForced(D, DeclAndTypeIDs); } 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: 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]; PatternBindingInitializerLayout::emitRecord(Out, ScratchRecord, abbrCode, addDeclRef(binding), bindingIndex); } 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."); } 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); } void Serializer::writeDecl(const Decl *D) { using namespace decls_block; auto id = DeclAndTypeIDs[D].first; assert(id != 0 && "decl or type not referenced properly"); (void)id; assert((id - 1) == DeclOffsets.size()); DeclOffsets.push_back(Out.GetCurrentBitNo()); 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)) { if (value->hasAccessibility() && value->getFormalAccess() <= Accessibility::FilePrivate && !value->getDeclContext()->isLocalContext()) { // 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. auto topLevelContext = value->getDeclContext()->getModuleScopeContext(); if (auto *enclosingFile = dyn_cast(topLevelContext)) { Identifier discriminator = enclosingFile->getDiscriminatorForPrivateValue(value); unsigned abbrCode = DeclTypeAbbrCodes[PrivateDiscriminatorLayout::Code]; PrivateDiscriminatorLayout::emitRecord(Out, ScratchRecord, abbrCode, addIdentifierRef(discriminator)); } } 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::Extension: { auto extension = cast(D); verifyAttrSerializable(extension); auto contextID = addDeclContextRef(extension->getDeclContext()); Type baseTy = extension->getExtendedType(); // 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, /*sorted=*/true); SmallVector inheritedTypes; for (auto inherited : extension->getInherited()) inheritedTypes.push_back(addTypeRef(inherited.getType())); unsigned abbrCode = DeclTypeAbbrCodes[ExtensionLayout::Code]; ExtensionLayout::emitRecord(Out, ScratchRecord, abbrCode, addTypeRef(baseTy), contextID, extension->isImplicit(), addGenericEnvironmentRef( extension->getGenericEnvironment()), conformances.size(), inheritedTypes); 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(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 = addIdentifierRef(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::InfixOperator: { auto op = cast(D); verifyAttrSerializable(op); auto contextID = addDeclContextRef(op->getDeclContext()); auto nameID = addIdentifierRef(op->getName()); auto groupID = addDeclRef(op->getPrecedenceGroup()); unsigned abbrCode = DeclTypeAbbrCodes[InfixOperatorLayout::Code]; InfixOperatorLayout::emitRecord(Out, ScratchRecord, abbrCode, nameID, contextID, groupID); break; } case DeclKind::PrefixOperator: { auto op = cast(D); verifyAttrSerializable(op); auto contextID = addDeclContextRef(op->getDeclContext()); unsigned abbrCode = DeclTypeAbbrCodes[PrefixOperatorLayout::Code]; PrefixOperatorLayout::emitRecord(Out, ScratchRecord, abbrCode, addIdentifierRef(op->getName()), contextID); break; } case DeclKind::PostfixOperator: { auto op = cast(D); verifyAttrSerializable(op); auto contextID = addDeclContextRef(op->getDeclContext()); unsigned abbrCode = DeclTypeAbbrCodes[PostfixOperatorLayout::Code]; PostfixOperatorLayout::emitRecord(Out, ScratchRecord, abbrCode, addIdentifierRef(op->getName()), contextID); 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(); uint8_t rawAccessLevel = getRawStableAccessibility(typeAlias->getFormalAccess()); unsigned abbrCode = DeclTypeAbbrCodes[TypeAliasLayout::Code]; TypeAliasLayout::emitRecord(Out, ScratchRecord, abbrCode, addIdentifierRef(typeAlias->getName()), contextID, addTypeRef(underlying), /*no longer used*/TypeID(), typeAlias->isImplicit(), addGenericEnvironmentRef( typeAlias->getGenericEnvironment()), rawAccessLevel); writeGenericParams(typeAlias->getGenericParams()); break; } case DeclKind::GenericTypeParam: { auto genericParam = cast(D); verifyAttrSerializable(genericParam); auto contextID = addDeclContextRef(genericParam->getDeclContext()); unsigned abbrCode = DeclTypeAbbrCodes[GenericTypeParamDeclLayout::Code]; GenericTypeParamDeclLayout::emitRecord(Out, ScratchRecord, abbrCode, addIdentifierRef(genericParam->getName()), contextID, genericParam->isImplicit(), genericParam->getDepth(), genericParam->getIndex()); break; } case DeclKind::AssociatedType: { auto assocType = cast(D); verifyAttrSerializable(assocType); auto contextID = addDeclContextRef(assocType->getDeclContext()); SmallVector inheritedTypes; for (auto inherited : assocType->getInherited()) inheritedTypes.push_back(addTypeRef(inherited.getType())); unsigned abbrCode = DeclTypeAbbrCodes[AssociatedTypeDeclLayout::Code]; AssociatedTypeDeclLayout::emitRecord( Out, ScratchRecord, abbrCode, addIdentifierRef(assocType->getName()), contextID, addTypeRef(assocType->getDefaultDefinitionType()), assocType->isImplicit(), inheritedTypes); break; } case DeclKind::Struct: { auto theStruct = cast(D); verifyAttrSerializable(theStruct); auto contextID = addDeclContextRef(theStruct->getDeclContext()); auto conformances = theStruct->getLocalConformances( ConformanceLookupKind::All, nullptr, /*sorted=*/true); SmallVector inheritedTypes; for (auto inherited : theStruct->getInherited()) inheritedTypes.push_back(addTypeRef(inherited.getType())); uint8_t rawAccessLevel = getRawStableAccessibility(theStruct->getFormalAccess()); unsigned abbrCode = DeclTypeAbbrCodes[StructLayout::Code]; StructLayout::emitRecord(Out, ScratchRecord, abbrCode, addIdentifierRef(theStruct->getName()), contextID, theStruct->isImplicit(), addGenericEnvironmentRef( theStruct->getGenericEnvironment()), rawAccessLevel, conformances.size(), inheritedTypes); writeGenericParams(theStruct->getGenericParams()); writeMembers(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, /*sorted=*/true); SmallVector inheritedTypes; for (auto inherited : theEnum->getInherited()) inheritedTypes.push_back(addTypeRef(inherited.getType())); uint8_t rawAccessLevel = getRawStableAccessibility(theEnum->getFormalAccess()); unsigned abbrCode = DeclTypeAbbrCodes[EnumLayout::Code]; EnumLayout::emitRecord(Out, ScratchRecord, abbrCode, addIdentifierRef(theEnum->getName()), contextID, theEnum->isImplicit(), addGenericEnvironmentRef( theEnum->getGenericEnvironment()), addTypeRef(theEnum->getRawType()), rawAccessLevel, conformances.size(), inheritedTypes); writeGenericParams(theEnum->getGenericParams()); writeMembers(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, /*sorted=*/true); SmallVector inheritedTypes; for (auto inherited : theClass->getInherited()) inheritedTypes.push_back(addTypeRef(inherited.getType())); uint8_t rawAccessLevel = getRawStableAccessibility(theClass->getFormalAccess()); unsigned abbrCode = DeclTypeAbbrCodes[ClassLayout::Code]; ClassLayout::emitRecord(Out, ScratchRecord, abbrCode, addIdentifierRef(theClass->getName()), contextID, theClass->isImplicit(), theClass->isObjC(), theClass->requiresStoredPropertyInits(), addGenericEnvironmentRef( theClass->getGenericEnvironment()), addTypeRef(theClass->getSuperclass()), rawAccessLevel, conformances.size(), inheritedTypes); writeGenericParams(theClass->getGenericParams()); writeMembers(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()) inherited.push_back(addTypeRef(element.getType())); uint8_t rawAccessLevel = getRawStableAccessibility(proto->getFormalAccess()); unsigned abbrCode = DeclTypeAbbrCodes[ProtocolLayout::Code]; ProtocolLayout::emitRecord(Out, ScratchRecord, abbrCode, addIdentifierRef(proto->getName()), contextID, proto->isImplicit(), const_cast(proto) ->requiresClass(), proto->isObjC(), addGenericEnvironmentRef( proto->getGenericEnvironment()), rawAccessLevel, inherited); writeGenericParams(proto->getGenericParams()); writeGenericRequirements( proto->getRequirementSignature()->getRequirements(), DeclTypeAbbrCodes); writeMembers(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 = getRawStableAccessibility(var->getFormalAccess()); uint8_t rawSetterAccessLevel = rawAccessLevel; if (var->isSettable(nullptr)) rawSetterAccessLevel = getRawStableAccessibility(var->getSetterAccessibility()); unsigned abbrCode = DeclTypeAbbrCodes[VarLayout::Code]; VarLayout::emitRecord(Out, ScratchRecord, abbrCode, addIdentifierRef(var->getName()), contextID, var->isImplicit(), var->isObjC(), var->isStatic(), var->isLet(), var->hasNonPatternBindingInit(), (unsigned) accessors.Kind, addTypeRef(var->getInterfaceType()), addDeclRef(accessors.Get), addDeclRef(accessors.Set), addDeclRef(accessors.MaterializeForSet), addDeclRef(accessors.Address), addDeclRef(accessors.MutableAddress), addDeclRef(accessors.WillSet), addDeclRef(accessors.DidSet), addDeclRef(var->getOverriddenDecl()), rawAccessLevel, rawSetterAccessLevel); break; } case DeclKind::Param: { auto param = cast(D); verifyAttrSerializable(param); auto contextID = addDeclContextRef(param->getDeclContext()); Type interfaceType = param->getInterfaceType(); unsigned abbrCode = DeclTypeAbbrCodes[ParamLayout::Code]; ParamLayout::emitRecord(Out, ScratchRecord, abbrCode, addIdentifierRef(param->getArgumentName()), addIdentifierRef(param->getName()), contextID, param->isLet(), addTypeRef(interfaceType)); 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 nameComponents; nameComponents.push_back(addIdentifierRef(fn->getFullName().getBaseName())); for (auto argName : fn->getFullName().getArgumentNames()) nameComponents.push_back(addIdentifierRef(argName)); uint8_t rawAccessLevel = getRawStableAccessibility(fn->getFormalAccess()); uint8_t rawAddressorKind = getRawStableAddressorKind(fn->getAddressorKind()); FuncLayout::emitRecord(Out, ScratchRecord, abbrCode, contextID, fn->isImplicit(), fn->isStatic(), uint8_t( getStableStaticSpelling(fn->getStaticSpelling())), fn->isObjC(), fn->isMutating(), fn->hasDynamicSelf(), fn->hasThrows(), fn->getParameterLists().size(), addGenericEnvironmentRef( fn->getGenericEnvironment()), addTypeRef(fn->getInterfaceType()), addDeclRef(fn->getOperatorDecl()), addDeclRef(fn->getOverriddenDecl()), addDeclRef(fn->getAccessorStorageDecl()), !fn->getFullName().isSimpleName(), rawAddressorKind, rawAccessLevel, nameComponents); writeGenericParams(fn->getGenericParams()); // Write the body parameters. for (auto pattern : fn->getParameterLists()) writeParameterList(pattern); if (auto errorConvention = fn->getForeignErrorConvention()) writeForeignErrorConvention(*errorConvention); break; } case DeclKind::EnumElement: { auto elem = cast(D); auto contextID = addDeclContextRef(elem->getDeclContext()); // 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(); } unsigned abbrCode = DeclTypeAbbrCodes[EnumElementLayout::Code]; EnumElementLayout::emitRecord(Out, ScratchRecord, abbrCode, addIdentifierRef(elem->getName()), contextID, addTypeRef(elem->getInterfaceType()), !!elem->getArgumentInterfaceType(), elem->isImplicit(), (unsigned)RawValueKind, Negative, RawValueText); break; } case DeclKind::Subscript: { auto subscript = cast(D); verifyAttrSerializable(subscript); auto contextID = addDeclContextRef(subscript->getDeclContext()); SmallVector nameComponents; for (auto argName : subscript->getFullName().getArgumentNames()) nameComponents.push_back(addIdentifierRef(argName)); Accessors accessors = getAccessors(subscript); uint8_t rawAccessLevel = getRawStableAccessibility(subscript->getFormalAccess()); uint8_t rawSetterAccessLevel = rawAccessLevel; if (subscript->isSettable()) rawSetterAccessLevel = getRawStableAccessibility(subscript->getSetterAccessibility()); unsigned abbrCode = DeclTypeAbbrCodes[SubscriptLayout::Code]; SubscriptLayout::emitRecord(Out, ScratchRecord, abbrCode, contextID, subscript->isImplicit(), subscript->isObjC(), (unsigned) accessors.Kind, addGenericEnvironmentRef( subscript->getGenericEnvironment()), addTypeRef(subscript->getInterfaceType()), addDeclRef(accessors.Get), addDeclRef(accessors.Set), addDeclRef(accessors.MaterializeForSet), addDeclRef(accessors.Address), addDeclRef(accessors.MutableAddress), addDeclRef(accessors.WillSet), addDeclRef(accessors.DidSet), addDeclRef(subscript->getOverriddenDecl()), rawAccessLevel, rawSetterAccessLevel, nameComponents); writeGenericParams(subscript->getGenericParams()); writeParameterList(subscript->getIndices()); break; } case DeclKind::Constructor: { auto ctor = cast(D); verifyAttrSerializable(ctor); auto contextID = addDeclContextRef(ctor->getDeclContext()); SmallVector nameComponents; for (auto argName : ctor->getFullName().getArgumentNames()) nameComponents.push_back(addIdentifierRef(argName)); uint8_t rawAccessLevel = getRawStableAccessibility(ctor->getFormalAccess()); 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()), addTypeRef(ctor->getInterfaceType()), addDeclRef(ctor->getOverriddenDecl()), rawAccessLevel, nameComponents); writeGenericParams(ctor->getGenericParams()); assert(ctor->getParameterLists().size() == 2); // Why is this writing out the param list for self? for (auto paramList : ctor->getParameterLists()) writeParameterList(paramList); if (auto errorConvention = ctor->getForeignErrorConvention()) writeForeignErrorConvention(*errorConvention); 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()), addTypeRef(dtor->getInterfaceType())); assert(dtor->getParameterLists().size() == 1); // Why is this writing out the param list for self? writeParameterList(dtor->getParameterLists()[0]); 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 ownership enum to the Serialization enum /// values, which are guaranteed to be stable. static uint8_t getRawStableOwnership(swift::Ownership ownership) { switch (ownership) { SIMPLE_CASE(Ownership, Strong) SIMPLE_CASE(Ownership, Weak) SIMPLE_CASE(Ownership, Unowned) SIMPLE_CASE(Ownership, Unmanaged) } 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_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, BuiltinType *Bt) { /// Get the type name by chopping off "Builtin.". llvm::SmallString<32> FullName; llvm::raw_svector_ostream OS(FullName); Bt->print(OS); assert(FullName.startswith("Builtin.")); 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; auto id = DeclAndTypeIDs[ty].first; assert(id != 0 && "type not referenced properly"); (void)id; assert((id - 1) == TypeOffsets.size()); TypeOffsets.push_back(Out.GetCurrentBitNo()); switch (ty.getPointer()->getKind()) { case TypeKind::Error: case TypeKind::Unresolved: llvm_unreachable("should not serialize an invalid type"); case TypeKind::BuiltinInteger: case TypeKind::BuiltinFloat: case TypeKind::BuiltinRawPointer: case TypeKind::BuiltinNativeObject: case TypeKind::BuiltinBridgeObject: case TypeKind::BuiltinUnknownObject: case TypeKind::BuiltinUnsafeValueBuffer: case TypeKind::BuiltinVector: { TypeAliasDecl *typeAlias = findTypeAliasForBuiltin(M->getASTContext(), ty->castTo()); unsigned abbrCode = DeclTypeAbbrCodes[NameAliasTypeLayout::Code]; NameAliasTypeLayout::emitRecord(Out, ScratchRecord, abbrCode, addDeclRef(typeAlias, /*forceSerialization*/false, /*allowTypeAliasXRef*/true), TypeID()); break; } case TypeKind::NameAlias: { auto nameAlias = cast(ty.getPointer()); const TypeAliasDecl *typeAlias = nameAlias->getDecl(); unsigned abbrCode = DeclTypeAbbrCodes[NameAliasTypeLayout::Code]; NameAliasTypeLayout::emitRecord(Out, ScratchRecord, abbrCode, addDeclRef(typeAlias, /*forceSerialization*/false, /*allowTypeAliasXRef*/true), addTypeRef(ty->getCanonicalType())); break; } case TypeKind::Paren: { auto parenTy = cast(ty.getPointer()); auto paramFlags = parenTy->getParameterFlags(); unsigned abbrCode = DeclTypeAbbrCodes[ParenTypeLayout::Code]; ParenTypeLayout::emitRecord( Out, ScratchRecord, abbrCode, addTypeRef(parenTy->getUnderlyingType()), paramFlags.isVariadic(), paramFlags.isAutoClosure(), paramFlags.isEscaping()); 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()) { auto paramFlags = elt.getParameterFlags(); TupleTypeEltLayout::emitRecord( Out, ScratchRecord, abbrCode, addIdentifierRef(elt.getName()), addTypeRef(elt.getType()), paramFlags.isVariadic(), paramFlags.isAutoClosure(), paramFlags.isEscaping()); } 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::Archetype: { auto archetypeTy = cast(ty.getPointer()); // Opened existential types use a separate layout. if (auto existentialTy = archetypeTy->getOpenedExistentialType()) { unsigned abbrCode = DeclTypeAbbrCodes[OpenedExistentialTypeLayout::Code]; OpenedExistentialTypeLayout::emitRecord(Out, ScratchRecord, abbrCode, addTypeRef(existentialTy)); break; } auto env = archetypeTy->getGenericEnvironment(); assert(env && "Primary archetype without generic environment?"); GenericEnvironmentID envID = addGenericEnvironmentRef(env); Type interfaceType = env->mapTypeOutOfContext(archetypeTy); unsigned abbrCode = DeclTypeAbbrCodes[ArchetypeTypeLayout::Code]; ArchetypeTypeLayout::emitRecord(Out, ScratchRecord, abbrCode, envID, addTypeRef(interfaceType)); 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: { auto fnTy = cast(ty.getPointer()); unsigned abbrCode = DeclTypeAbbrCodes[FunctionTypeLayout::Code]; FunctionTypeLayout::emitRecord(Out, ScratchRecord, abbrCode, addTypeRef(fnTy->getInput()), addTypeRef(fnTy->getResult()), getRawStableFunctionTypeRepresentation(fnTy->getRepresentation()), fnTy->isAutoClosure(), fnTy->isNoEscape(), fnTy->throws()); break; } case TypeKind::GenericFunction: { auto fnTy = cast(ty.getPointer()); unsigned abbrCode = DeclTypeAbbrCodes[GenericFunctionTypeLayout::Code]; SmallVector genericParams; for (auto param : fnTy->getGenericParams()) genericParams.push_back(addTypeRef(param)); GenericFunctionTypeLayout::emitRecord(Out, ScratchRecord, abbrCode, addTypeRef(fnTy->getInput()), addTypeRef(fnTy->getResult()), getRawStableFunctionTypeRepresentation(fnTy->getRepresentation()), fnTy->throws(), genericParams); // Write requirements. writeGenericRequirements(fnTy->getRequirements(), DeclTypeAbbrCodes); 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()); #ifndef NDEBUG if (auto sig = boxTy->getLayout()->getGenericSignature()) { assert(sig->getSubstitutionListSize() == boxTy->getGenericArgs().size()); } #endif SILBoxTypeLayout::emitRecord(Out, ScratchRecord, abbrCode, layoutRef); // Write the set of substitutions. writeSubstitutions(boxTy->getGenericArgs(), DeclTypeAbbrCodes); 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 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(); if (sig) { for (auto param : sig->getGenericParams()) variableData.push_back(addTypeRef(param)); } auto stableCalleeConvention = getRawStableParameterConvention(fnTy->getCalleeConvention()); unsigned abbrCode = DeclTypeAbbrCodes[SILFunctionTypeLayout::Code]; SILFunctionTypeLayout::emitRecord( Out, ScratchRecord, abbrCode, stableCalleeConvention, stableRepresentation, fnTy->isPseudogeneric(), fnTy->hasErrorResult(), fnTy->getParameters().size(), fnTy->getNumResults(), variableData); if (sig) writeGenericRequirements(sig->getRequirements(), 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::ImplicitlyUnwrappedOptional: { auto optionalTy = cast(ty.getPointer()); Type base = optionalTy->getBaseType(); unsigned abbrCode = DeclTypeAbbrCodes[ImplicitlyUnwrappedOptionalTypeLayout::Code]; ImplicitlyUnwrappedOptionalTypeLayout::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; } case TypeKind::LValue: { auto lValueTy = cast(ty.getPointer()); unsigned abbrCode = DeclTypeAbbrCodes[LValueTypeLayout::Code]; LValueTypeLayout::emitRecord(Out, ScratchRecord, abbrCode, addTypeRef(lValueTy->getObjectType())); break; } case TypeKind::InOut: { auto iotTy = cast(ty.getPointer()); unsigned abbrCode = DeclTypeAbbrCodes[InOutTypeLayout::Code]; InOutTypeLayout::emitRecord(Out, ScratchRecord, abbrCode, addTypeRef(iotTy->getObjectType())); break; } case TypeKind::UnownedStorage: case TypeKind::UnmanagedStorage: case TypeKind::WeakStorage: { auto refTy = cast(ty.getPointer()); unsigned abbrCode = DeclTypeAbbrCodes[ReferenceStorageTypeLayout::Code]; auto stableOwnership = getRawStableOwnership(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()), 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::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(); #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 (!GenericEnvironmentsToWrite.empty()) { auto next = GenericEnvironmentsToWrite.front(); GenericEnvironmentsToWrite.pop(); writeGenericEnvironment(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() || !GenericEnvironmentsToWrite.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 (Identifier ident : IdentifiersToWrite) { IdentifierOffsets.push_back(stringData.size()); stringData.append(ident.get()); 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::Writer(blobStream).write(0); 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::Writer(blobStream).write(0); 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::Writer(blobStream).write(0); 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::Writer(blobStream).write(0); tableOffset = generator.Emit(blobStream); } declList.emit(scratch, tableOffset, hashTableBlob); } namespace { struct DeclCommentTableData { StringRef Brief; RawComment Raw; uint32_t Group; uint32_t Order; }; class DeclCommentTableInfo { public: using key_type = StringRef; using key_type_ref = key_type; using data_type = DeclCommentTableData; using data_type_ref = const data_type &; using hash_value_type = uint32_t; using offset_type = unsigned; hash_value_type ComputeHash(key_type_ref key) { assert(!key.empty()); return llvm::HashString(key); } std::pair EmitKeyDataLength(raw_ostream &out, key_type_ref key, data_type_ref data) { uint32_t keyLength = key.size(); const unsigned numLen = 4; // Data consists of brief comment length and brief comment text, uint32_t dataLength = numLen + data.Brief.size(); // number of raw comments, dataLength += numLen; // for each raw comment: column number of the first line, length of each // raw comment and its text. for (auto C : data.Raw.Comments) dataLength += numLen + numLen + C.RawText.size(); // Group Id. dataLength += numLen; // Source order. dataLength += numLen; endian::Writer writer(out); writer.write(keyLength); writer.write(dataLength); return { keyLength, dataLength }; } void EmitKey(raw_ostream &out, key_type_ref key, unsigned len) { out << key; } void EmitData(raw_ostream &out, key_type_ref key, data_type_ref data, unsigned len) { endian::Writer writer(out); writer.write(data.Brief.size()); out << data.Brief; writer.write(data.Raw.Comments.size()); for (auto C : data.Raw.Comments) { writer.write(C.StartColumn); writer.write(C.RawText.size()); out << C.RawText; } writer.write(data.Group); writer.write(data.Order); } }; } // end unnamed namespace typedef llvm::StringMap FileNameToGroupNameMap; typedef std::unique_ptr pFileNameToGroupNameMap; class YamlGroupInputParser { StringRef RecordPath; std::string Separator = "/"; static llvm::StringMap AllMaps; bool parseRoot(FileNameToGroupNameMap &Map, llvm::yaml::Node *Root, const llvm::Twine &ParentName) { llvm::yaml::MappingNode *MapNode = dyn_cast(Root); if (!MapNode) { return true; } for (auto Pair : *MapNode) { auto *Key = dyn_cast_or_null(Pair.getKey()); auto *Value = dyn_cast_or_null(Pair.getValue()); if (!Key || !Value) { return true; } llvm::SmallString<16> GroupNameStorage; StringRef GroupName = Key->getValue(GroupNameStorage); std::unique_ptr pCombined; if (!ParentName.isTriviallyEmpty()) { pCombined.reset(new llvm::Twine(ParentName.concat(Separator). concat(GroupName))); } else { pCombined.reset(new llvm::Twine(GroupName)); } std::string CombinedName = pCombined->str(); for (llvm::yaml::Node &Entry : *Value) { if (auto *FileEntry= dyn_cast(&Entry)) { llvm::SmallString<16> FileNameStorage; StringRef FileName = FileEntry->getValue(FileNameStorage); llvm::SmallString<32> GroupNameAndFileName; GroupNameAndFileName.append(CombinedName); GroupNameAndFileName.append(Separator); GroupNameAndFileName.append(llvm::sys::path::stem(FileName)); Map[FileName] = GroupNameAndFileName.str(); } else if (Entry.getType() == llvm::yaml::Node::NodeKind::NK_Mapping) { if (parseRoot(Map, &Entry, *pCombined)) return true; } else return true; } } return false; } public: YamlGroupInputParser(StringRef RecordPath): RecordPath(RecordPath) {} FileNameToGroupNameMap* getParsedMap() { return AllMaps[RecordPath].get(); } // Parse the Yaml file that contains the group information. // True on failure; false on success. bool parse() { // If we have already parsed this group info file, return false; auto FindMap = AllMaps.find(RecordPath); if (FindMap != AllMaps.end()) return false; auto Buffer = llvm::MemoryBuffer::getFile(RecordPath); if (!Buffer) { // The group info file does not exist. return true; } llvm::SourceMgr SM; llvm::yaml::Stream YAMLStream(Buffer.get()->getMemBufferRef(), SM); llvm::yaml::document_iterator I = YAMLStream.begin(); if (I == YAMLStream.end()) { // Cannot parse correctly. return true; } llvm::yaml::Node *Root = I->getRoot(); if (!Root) { // Cannot parse correctly. return true; } // The format is a map of ("group0" : ["file1", "file2"]), meaning all // symbols from file1 and file2 belong to "group0". llvm::yaml::MappingNode *Map = dyn_cast(Root); if (!Map) { return true; } pFileNameToGroupNameMap pMap(new FileNameToGroupNameMap()); if (parseRoot(*pMap, Root, llvm::Twine())) return true; // Save the parsed map to the owner. AllMaps[RecordPath] = std::move(pMap); return false; } }; llvm::StringMap YamlGroupInputParser::AllMaps; class DeclGroupNameContext { struct GroupNameCollector { const std::string NullGroupName = ""; const bool Enable; GroupNameCollector(bool Enable) : Enable(Enable) {} virtual ~GroupNameCollector() = default; virtual StringRef getGroupNameInternal(const Decl *VD) = 0; StringRef getGroupName(const Decl *VD) { return Enable ? getGroupNameInternal(VD) : StringRef(NullGroupName); }; }; class GroupNameCollectorFromJson : public GroupNameCollector { StringRef RecordPath; FileNameToGroupNameMap* pMap = nullptr; ASTContext &Ctx; public: GroupNameCollectorFromJson(StringRef RecordPath, ASTContext &Ctx) : GroupNameCollector(!RecordPath.empty()), RecordPath(RecordPath), Ctx(Ctx) {} StringRef getGroupNameInternal(const Decl *VD) override { // We need the file path, so there has to be a location. if (VD->getLoc().isInvalid()) return NullGroupName; auto PathOp = VD->getDeclContext()->getParentSourceFile()->getBufferID(); if (!PathOp.hasValue()) return NullGroupName; StringRef FullPath = VD->getASTContext().SourceMgr.getIdentifierForBuffer(PathOp.getValue()); if (!pMap) { YamlGroupInputParser Parser(RecordPath); if (!Parser.parse()) { // Get the file-name to group map if parsing correctly. pMap = Parser.getParsedMap(); } } if (!pMap) return NullGroupName; StringRef FileName = llvm::sys::path::filename(FullPath); auto Found = pMap->find(FileName); if (Found == pMap->end()) { Ctx.Diags.diagnose(SourceLoc(), diag::error_no_group_info, FileName); return NullGroupName; } return Found->second; } }; llvm::MapVector Map; std::vector ViewBuffer; std::unique_ptr pNameCollector; public: DeclGroupNameContext(StringRef RecordPath, ASTContext &Ctx) : pNameCollector(new GroupNameCollectorFromJson(RecordPath, Ctx)) {} uint32_t getGroupSequence(const Decl *VD) { return Map.insert(std::make_pair(pNameCollector->getGroupName(VD), Map.size())).first->second; } ArrayRef getOrderedGroupNames() { ViewBuffer.clear(); for (auto It = Map.begin(); It != Map.end(); ++ It) { ViewBuffer.push_back(It->first); } return llvm::makeArrayRef(ViewBuffer); } bool isEnable() { return pNameCollector->Enable; } }; static void writeGroupNames(const comment_block::GroupNamesLayout &GroupNames, ArrayRef Names) { llvm::SmallString<32> Blob; llvm::raw_svector_ostream BlobStream(Blob); endian::Writer Writer(BlobStream); Writer.write(Names.size()); for (auto N : Names) { Writer.write(N.size()); BlobStream << N; } SmallVector Scratch; GroupNames.emit(Scratch, BlobStream.str()); } static void writeDeclCommentTable( const comment_block::DeclCommentListLayout &DeclCommentList, const SourceFile *SF, const ModuleDecl *M, DeclGroupNameContext &GroupContext) { struct DeclCommentTableWriter : public ASTWalker { llvm::BumpPtrAllocator Arena; llvm::SmallString<512> USRBuffer; llvm::OnDiskChainedHashTableGenerator generator; DeclGroupNameContext &GroupContext; unsigned SourceOrder; DeclCommentTableWriter(DeclGroupNameContext &GroupContext) : GroupContext(GroupContext) {} void resetSourceOrder() { SourceOrder = 0; } StringRef copyString(StringRef String) { char *Mem = static_cast(Arena.Allocate(String.size(), 1)); std::copy(String.begin(), String.end(), Mem); return StringRef(Mem, String.size()); } void writeDocForExtensionDecl(ExtensionDecl *ED) { RawComment Raw = ED->getRawComment(); if (Raw.Comments.empty() && !GroupContext.isEnable()) return; // Compute USR. { USRBuffer.clear(); llvm::raw_svector_ostream OS(USRBuffer); if (ide::printExtensionUSR(ED, OS)) return; } generator.insert(copyString(USRBuffer.str()), { ED->getBriefComment(), Raw, GroupContext.getGroupSequence(ED), SourceOrder++ }); } bool walkToDeclPre(Decl *D) override { if (auto *ED = dyn_cast(D)) { writeDocForExtensionDecl(ED); return true; } auto *VD = dyn_cast(D); if (!VD) return true; RawComment Raw = VD->getRawComment(); // When building the stdlib we intend to // serialize unusual comments. This situation is represented by // GroupContext.isEnable(). In that case, we perform fewer serialization checks. if (!GroupContext.isEnable()) { // Skip the decl if it cannot have a comment. if (!VD->canHaveComment()) { return true; } // Skip the decl if it does not have a comment. if (Raw.Comments.empty()) return true; // Skip the decl if it's not visible to clients. // The use of getEffectiveAccess is unusual here; // we want to take the testability state into account // and emit documentation if and only if they are visible to clients // (which means public ordinarily, but public+internal when testing enabled). if (VD->getEffectiveAccess() < Accessibility::Public) return true; } // Compute USR. { USRBuffer.clear(); llvm::raw_svector_ostream OS(USRBuffer); if (ide::printDeclUSR(VD, OS)) return true; } generator.insert(copyString(USRBuffer.str()), { VD->getBriefComment(), Raw, GroupContext.getGroupSequence(VD), SourceOrder++ }); return true; } }; DeclCommentTableWriter Writer(GroupContext); ArrayRef files; SmallVector Scratch; if (SF) { Scratch.push_back(SF); files = llvm::makeArrayRef(Scratch); } else { files = M->getFiles(); } for (auto nextFile : files) { Writer.resetSourceOrder(); const_cast(nextFile)->walk(Writer); } SmallVector scratch; llvm::SmallString<32> hashTableBlob; uint32_t tableOffset; { llvm::raw_svector_ostream blobStream(hashTableBlob); // Make sure that no bucket is at offset 0 endian::Writer(blobStream).write(0); tableOffset = Writer.generator.Emit(blobStream); } DeclCommentList.emit(scratch, tableOffset, hashTableBlob); } namespace { /// Used to serialize the on-disk Objective-C method hash table. class ObjCMethodTableInfo { public: using key_type = ObjCSelector; using key_type_ref = key_type; using data_type = Serializer::ObjCMethodTableData; using data_type_ref = const data_type &; using hash_value_type = uint32_t; using offset_type = unsigned; hash_value_type ComputeHash(key_type_ref key) { llvm::SmallString<32> scratch; return llvm::HashString(key.getString(scratch)); } 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); 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); 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::Writer(blobStream).write(0); 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 (auto memberValue = dyn_cast(member)) { if (!memberValue->hasName()) 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->getName()].push_back({ /*ignored*/0, S.addDeclRef(memberValue) }); } } if (auto nestedType = dyn_cast(member)) { if (nestedType->getEffectiveAccess() > Accessibility::FilePrivate) { if (!nominalParent) { const DeclContext *DC = member->getDeclContext(); nominalParent = DC->getAsNominalTypeOrNominalTypeExtensionContext(); 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. if (!isLocal) { if (auto func = dyn_cast(member)) { if (func->isObjC()) { if (auto owningClass = func->getDeclContext()->getAsClassOrClassExtensionContext()) { 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))); } } } } } } 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; 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)) continue; if (auto VD = dyn_cast(D)) { if (!VD->hasName()) continue; topLevelDecls[VD->getName()] .push_back({ getKindForTable(D), addDeclRef(D) }); } else if (auto ED = dyn_cast(D)) { Type extendedTy = ED->getExtendedType(); const NominalTypeDecl *extendedNominal = extendedTy->getAnyNominal(); 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) }); } // 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 = Mangler.mangleTypeAsUSR( TD->getDeclaredInterfaceType()); assert(!MangledName.empty() && "Mangled type came back empty!"); localTypeGenerator.insert(MangledName, { addDeclRef(TD), TD->getLocalDiscriminator() }); 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, GenericEnvironmentOffsets); 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, ClassMembersByName); 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::ObjCMethodTableLayout ObjCMethodTable(Out); writeObjCMethodTable(ObjCMethodTable, objcMethods); if (DC.is() && enableNestedTypeLookupTable && !nestedTypeDecls.empty()) { index_block::NestedTypeDeclsLayout NestedTypeDeclsTable(Out); writeNestedTypeDeclsTable(NestedTypeDeclsTable, nestedTypeDecls); } if (entryPointClassID.hasValue()) { index_block::EntryPointLayout EntryPoint(Out); EntryPoint.emit(ScratchRecord, entryPointClassID.getValue()); } } } void Serializer::writeToStream(raw_ostream &os) { os.write(Buffer.data(), Buffer.size()); os.flush(); } template Serializer::Serializer(const unsigned char (&signature)[N], 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{MODULE_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 Serializer::writeDocToStream(raw_ostream &os, ModuleOrSourceFile DC, StringRef GroupInfoPath, ASTContext &Ctx) { Serializer S{MODULE_DOC_SIGNATURE, DC}; // FIXME: This is only really needed for debugging. We don't actually use it. S.writeDocBlockInfoBlock(); { BCBlockRAII moduleBlock(S.Out, MODULE_DOC_BLOCK_ID, 2); S.writeDocHeader(); { BCBlockRAII restoreBlock(S.Out, COMMENT_BLOCK_ID, 4); DeclGroupNameContext GroupContext(GroupInfoPath, Ctx); comment_block::DeclCommentListLayout DeclCommentList(S.Out); writeDeclCommentTable(DeclCommentList, S.SF, S.M, GroupContext); comment_block::GroupNamesLayout GroupNames(S.Out); // FIXME: Multi-file compilation may cause group id collision. writeGroupNames(GroupNames, GroupContext.getOrderedGroupNames()); } } S.writeToStream(os); } static inline bool withOutputFile(ASTContext &ctx, StringRef outputPath, llvm::function_ref action){ namespace path = llvm::sys::path; clang::CompilerInstance Clang; std::string tmpFilePath; { std::error_code EC; std::unique_ptr out = Clang.createOutputFile(outputPath, EC, /*Binary=*/true, /*RemoveFileOnSignal=*/true, /*BaseInput=*/"", path::extension(outputPath), /*UseTemporary=*/true, /*CreateMissingDirectories=*/false, /*ResultPathName=*/nullptr, &tmpFilePath); if (!out) { StringRef problematicPath = tmpFilePath.empty() ? outputPath : StringRef(tmpFilePath); ctx.Diags.diagnose(SourceLoc(), diag::error_opening_output, problematicPath, EC.message()); return true; } action(*out); } if (!tmpFilePath.empty()) { std::error_code EC = swift::moveFileIfDifferent(tmpFilePath, outputPath); if (EC) { ctx.Diags.diagnose(SourceLoc(), diag::error_opening_output, outputPath, EC.message()); return true; } } return false; } 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), options.OutputPath, [&](raw_ostream &out) { SharedTimer timer("Serialization, swiftmodule"); Serializer::writeToStream(out, DC, M, options); }); if (hadError) return; if (options.DocOutputPath && options.DocOutputPath[0] != '\0') { (void)withOutputFile(getContext(DC), options.DocOutputPath, [&](raw_ostream &out) { SharedTimer timer("Serialization, swiftdoc"); Serializer::writeDocToStream(out, DC, options.GroupInfoPath, getContext(DC)); }); } }