//===--- Serialization.h - Read and write Swift modules ---------*- C++ -*-===// // // 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 // //===----------------------------------------------------------------------===// // // This file defines the Serializer interface. // //===----------------------------------------------------------------------===// #ifndef SWIFT_SERIALIZATION_SERIALIZATION_H #define SWIFT_SERIALIZATION_SERIALIZATION_H #include "ModuleFormat.h" #include "swift/Basic/LLVMExtras.h" #include "swift/Serialization/SerializationOptions.h" #include "swift/Subsystems.h" #include "swift/AST/Identifier.h" #include "swift/AST/RequirementSignature.h" #include "swift/Basic/LLVM.h" #include "llvm/ADT/MapVector.h" #include #include #include namespace clang { class Type; } namespace swift { class SILModule; namespace fine_grained_dependencies { class SourceFileDepGraph; } namespace serialization { using FilenamesTy = ArrayRef; class SerializerBase { protected: SmallVector Buffer; llvm::BitstreamWriter Out{Buffer}; /// A reusable buffer for emitting records. SmallVector ScratchRecord; /// The module currently being serialized. const ModuleDecl *M = nullptr; /// The SourceFile currently being serialized, if any. /// /// If this is non-null, only decls actually from this SourceFile will be /// serialized. Any other decls will be cross-referenced instead. const SourceFile *SF = nullptr; /// Record the name of a block. void emitBlockID(unsigned ID, StringRef name, SmallVectorImpl &nameBuffer); /// Record the name of a record within a block. void emitRecordID(unsigned ID, StringRef name, SmallVectorImpl &nameBuffer, SmallVectorImpl *wideNameBuffer = nullptr); void writeToStream(raw_ostream &os); public: SerializerBase(ArrayRef signature, ModuleOrSourceFile DC); ASTContext &getASTContext() const; }; class Serializer : public SerializerBase { class DeclSerializer; friend class DeclSerializer; class TypeSerializer; friend class TypeSerializer; const SerializationOptions &Options; /// A map from non-identifier uniqued strings to their serialized IDs. /// /// Since we never remove items from this map, we can use a BumpPtrAllocator /// to back the entries. llvm::StringMap UniquedStringIDs; /// A map from Identifiers to their serialized IDs. /// /// This is stored separately from \p UniquedStringIDs because it's faster /// to do lookups in, even though that may lead to some duplication between /// identifier and non-identifier strings. llvm::DenseMap IdentifierIDs; /// All uniqued strings that need to be serialized (identifiers and /// non-identifiers). std::vector StringsToWrite; /// The last assigned IdentifierID for uniqued strings from this module. /// /// Note that special module IDs and IDs of special names must not be valid /// IdentifierIDs, except that 0 will always represent the empty identifier. uint32_t /*IdentifierID*/ LastUniquedStringID = serialization::NUM_SPECIAL_IDS - 1; SmallVector exportedPrespecializationDecls; /// Will be set to true if any serialization step failed, for example due to /// an error in the AST. bool hadError = false; /// Helper for serializing entities in the AST block object graph. /// /// Keeps track of assigning IDs to newly-seen entities, and collecting /// offsets when those entities are ready to be serialized. /// /// \tparam T The AST type that's being serialized /// \tparam ID The ID type for encoding into the bitstream /// \tparam RecordCode_ The code for the offsets record in the Index block for /// referring to these entities. template class ASTBlockRecordKeeper { /// Map of entities to assigned ID numbers. llvm::DenseMap IDs; /// All entities that still need to be written. /// /// This is a queue and not simply a vector because serializing one /// entity might result in another one getting queued up. std::queue EntitiesToWrite; /// The offsets of entities that have already been written. /// /// `Offsets[entityID - 1]` gives the offset for a particular entity. (0 is /// reserved for "empty" entities.) std::vector Offsets; public: /// The code for the offsets record in the Index block for referring to /// these entities. static const unsigned RecordCode = RecordCode_; /// Assigns \p entity an ID and schedules it for writing. /// /// If \p entity has been seen before, returns the existing ID. /// /// 0 is used for "empty" entities (those that coerce to \c false ). ID addRef(T entity) { assert(ID() == 0 && "bad default constructor for ID"); if (!entity) return 0; auto &entityID = IDs[entity]; if (entityID == ID()) { EntitiesToWrite.push(entity); entityID = IDs.size(); } return entityID; } /// Returns true if \p entity has been seen before (i.e. ever passed to /// #addRef). bool hasRef(T entity) const { return IDs.find(entity) != IDs.end(); } bool hasMoreToSerialize() const { return !EntitiesToWrite.empty(); } /// Returns the next entity to be written. /// /// If there is nothing left to serialize, returns None. std::optional peekNext() const { if (!hasMoreToSerialize()) return std::nullopt; return EntitiesToWrite.front(); } /// Records that the next entity will be written at \p offset, and returns /// it so it can be written. /// /// If there is nothing left to serialize, returns None. std::optional popNext(BitOffset offset) { if (!hasMoreToSerialize()) return std::nullopt; T result = EntitiesToWrite.front(); EntitiesToWrite.pop(); Offsets.push_back(offset); assert(IDs.lookup(result) == Offsets.size()); return result; } /// Returns the offsets for all entities that have been written. /// /// Should only be called after all entities \e have been written. ArrayRef getOffsets() const { assert(!hasMoreToSerialize() && "not all entities were serialized"); return Offsets; } }; ASTBlockRecordKeeper DeclsToSerialize; ASTBlockRecordKeeper TypesToSerialize; ASTBlockRecordKeeper ClangTypesToSerialize; ASTBlockRecordKeeper LocalDeclContextsToSerialize; ASTBlockRecordKeeper GenericSignaturesToSerialize; ASTBlockRecordKeeper GenericEnvironmentsToSerialize; ASTBlockRecordKeeper SubstitutionMapsToSerialize; ASTBlockRecordKeeper ConformancesToSerialize; ASTBlockRecordKeeper AbstractConformancesToSerialize; ASTBlockRecordKeeper PackConformancesToSerialize; ASTBlockRecordKeeper SILLayoutsToSerialize; public: using DeclTableData = SmallVector, 4>; /// The in-memory representation of what will eventually be an on-disk hash /// table. using DeclTable = llvm::MapVector; using ObjCMethodTableData = SmallVector, 4>; // In-memory representation of what will eventually be an on-disk // hash table of all defined Objective-C methods. using ObjCMethodTable = llvm::MapVector; using NestedTypeDeclsData = SmallVector, 4>; // In-memory representation of what will eventually be an on-disk // hash table of all defined Objective-C methods. using NestedTypeDeclsTable = llvm::MapVector; using DeclMembersData = SmallVector; // In-memory representation of what will eventually be an on-disk // hash table of all ValueDecl-members of a particular DeclBaseName. using DeclMembersTable = llvm::MapVector; using DeclMemberNamesData = std::pair>; // In-memory representation of what will eventually be an on-disk // hash table mapping DeclBaseNames to DeclMembersData tables. using DeclMemberNamesTable = llvm::MapVector; using ExtensionTableData = SmallVector, 4>; using ExtensionTable = llvm::MapVector; using DerivativeFunctionConfigTableData = llvm::SmallVector, 4>; // In-memory representation of what will eventually be an on-disk hash table // mapping original declaration USRs to derivative function configurations. using DerivativeFunctionConfigTable = llvm::MapVector; // Uniqued mapping from original declarations USRs to derivative function // configurations. // Note: this exists because `GenericSignature` can be used as a `DenseMap` // key, while `GenericSignatureID` cannot // (`DenseMapInfo::getEmptyKey()` crashes). To work // around this, a `UniquedDerivativeFunctionConfigTable` is first // constructed, and then converted to a `DerivativeFunctionConfigTableData`. using UniquedDerivativeFunctionConfigTable = llvm::MapVector< Identifier, swift::SmallSetVector, 4>>; // In-memory representation of what will eventually be an on-disk // hash table of the fingerprint associated with a serialized // iterable decl context. It is keyed by that context's decl ID. using DeclFingerprintsTable = llvm::MapVector; private: /// A map from identifiers to methods and properties with the given name. /// /// This is used for id-style lookup. DeclTable ClassMembersForDynamicLookup; /// A map from DeclBaseNames of members to Decl->members sub-tables. /// /// This is for Named Lazy Member Loading. DeclMemberNamesTable DeclMemberNames; enum {NumDeclTypeAbbrCodes = 512}; /// The abbreviation code for each record in the "decls-and-types" block. /// /// These are registered up front when entering the block, so they can be /// reused. std::array DeclTypeAbbrCodes; /// The decls that adopt compiler-known protocols. SmallVector KnownProtocolAdopters[NumKnownProtocols]; /// Writes the BLOCKINFO block for the serialized module file. void writeBlockInfoBlock(); /// Writes the Swift module file header and name, plus metadata determining /// if the module can be loaded. void writeHeader(); /// Writes the dependencies used to build this module: its imported /// modules and its source files. void writeInputBlock(); /// Check if a decl is cross-referenced. bool isDeclXRef(const Decl *D) const; /// Check if a decl should be skipped during serialization. bool shouldSkipDecl(const Decl *D) const; /// Writes a reference to a decl in another module. void writeCrossReference(const DeclContext *DC, uint32_t pathLen = 1); /// Writes a reference to a decl in another module. void writeCrossReference(const Decl *D); /// Writes the given decl. void writeASTBlockEntity(const Decl *D); /// Write a DeclContext as a local DeclContext at the current offset. void writeASTBlockEntity(const DeclContext *DC); /// Write the components of a PatternBindingInitializer as a local context. void writePatternBindingInitializer(PatternBindingDecl *binding, unsigned bindingIndex); /// Write the components of a DefaultArgumentInitializer as a local context. void writeDefaultArgumentInitializer(const DeclContext *parentContext, unsigned index); /// Write the components of an AbstractClosureExpr as a local context. void writeAbstractClosureExpr(const DeclContext *parentContext, Type Ty, bool isImplicit, unsigned discriminator); /// Writes the given type. void writeASTBlockEntity(Type ty); /// Writes the given Clang type. void writeASTBlockEntity(const clang::Type *ty); /// Writes a generic signature. void writeASTBlockEntity(GenericSignature sig); /// Writes a generic environment. void writeASTBlockEntity(const GenericEnvironment *env); /// Writes a substitution map. void writeASTBlockEntity(const SubstitutionMap substitutions); /// Writes a protocol conformance. void writeASTBlockEntity(ProtocolConformance *conformance); void writeLocalNormalProtocolConformance(NormalProtocolConformance *); /// Writes an abstract conformance. void writeASTBlockEntity(AbstractConformance *conformance); /// Writes a pack conformance. void writeASTBlockEntity(PackConformance *conformance); /// Writes lifetime dependencies void writeLifetimeDependencies( ArrayRef lifetimeDependenceInfo); /// Registers the abbreviation for the given decl or type layout. template void registerDeclTypeAbbr() { using AbbrArrayTy = decltype(DeclTypeAbbrCodes); static_assert(Layout::Code <= std::tuple_size::value, "layout has invalid record code"); DeclTypeAbbrCodes[Layout::Code] = Layout::emitAbbrev(Out); } /// Writes all queued \p entities until there are no more. /// /// \returns true if any entities were written template bool writeASTBlockEntitiesIfNeeded(SpecificASTBlockRecordKeeper &entities); /// Writes all decls and types in the DeclsToWrite queue. /// /// This will continue until the queue is empty, even if the items currently /// in the queue trigger the serialization of additional decls and/or types. void writeAllDeclsAndTypes(); /// Writes all identifiers in the IdentifiersToWrite queue. /// /// This must be called after writeAllDeclsAndTypes(), since that may add /// additional identifiers to the pool. std::vector writeAllIdentifiers(); /// Writes the offsets for a serialized entity kind. /// /// \see ASTBlockRecordKeeper template void writeOffsets(const index_block::OffsetsLayout &Offsets, const SpecificASTBlockRecordKeeper &entities); /// Serializes all transparent SIL functions in the SILModule. void writeSIL(const SILModule *M, bool serializeAllSIL, bool serializeDebugInfo); /// Top-level entry point for serializing a module. void writeAST(ModuleOrSourceFile DC); /// Serializes the given dependency graph into the incremental information /// section of this swift module. void writeIncrementalInfo( const fine_grained_dependencies::SourceFileDepGraph *DepGraph); using SerializerBase::SerializerBase; using SerializerBase::writeToStream; public: Serializer(ArrayRef signature, ModuleOrSourceFile DC, const SerializationOptions &options) : SerializerBase(signature, DC), Options(options) {} /// Serialize a module to the given stream. static void writeToStream(raw_ostream &os, ModuleOrSourceFile DC, const SILModule *M, const SerializationOptions &options, const fine_grained_dependencies::SourceFileDepGraph *DepGraph); /// Records the use of the given Type. /// /// The Type will be scheduled for serialization if necessary. /// /// \returns The ID for the given Type in this module. TypeID addTypeRef(Type ty); /// Records the use of the given C type. /// /// The type will be scheduled for serialization if necessary., /// /// \returns The ID for the given type in this module. ClangTypeID addClangTypeRef(const clang::Type *ty); /// Records the use of the given DeclBaseName. /// /// The Identifier will be scheduled for serialization if necessary. /// /// \returns The ID for the given DeclBaseName in this module. IdentifierID addDeclBaseNameRef(DeclBaseName ident); /// Records the use of the given string, which will only be stored once in /// the resulting module file. /// /// \returns A pair containing the copy of the string now owned by the /// Serializer and the ID for the string in this module. /// \sa addUniquedStringRef std::pair addUniquedString(StringRef str); /// Records the use of the given string, which will only be stored once in /// the resulting module file. /// /// \returns The ID for the given string in this module. /// \sa addUniquedString IdentifierID addUniquedStringRef(StringRef str) { return addUniquedString(str).second; } /// Records the use of the given file name. /// /// The Identifier will be scheduled for serialization if necessary. /// /// \returns The ID for the given file name in this module. IdentifierID addFilename(StringRef filename); /// Records the use of the given Decl. /// /// The Decl will be scheduled for serialization if necessary. /// /// \returns The ID for the given Decl in this module. DeclID addDeclRef(const Decl *D, bool allowTypeAliasXRef = false); /// Records the use of the given DeclContext. /// /// The DeclContext will be scheduled for serialization if necessary. DeclContextID addDeclContextRef(const DeclContext *DC); /// Records the use of the given local DeclContext. /// /// The DeclContext will be scheduled for serialization if necessary. LocalDeclContextID addLocalDeclContextRef(const DeclContext *DC); /// Records the use of the given generic signature. /// /// The GenericSignature will be scheduled for serialization if necessary. GenericSignatureID addGenericSignatureRef(GenericSignature sig); /// Records the use of the given opened generic environment. GenericEnvironmentID addGenericEnvironmentRef(GenericEnvironment *env); /// Records the use of the given substitution map. /// /// The SubstitutionMap will be scheduled for serialization if necessary. SubstitutionMapID addSubstitutionMapRef(SubstitutionMap substitutions); /// Records the use of the given protocol conformance. /// /// The protocol conformance will be scheduled for serialization /// if necessary. /// /// \returns The ID for the given conformance in this module. ProtocolConformanceID addConformanceRef(ProtocolConformance *conformance); ProtocolConformanceID addConformanceRef(PackConformance *conformance); ProtocolConformanceID addConformanceRef(ProtocolConformanceRef conformance); SmallVector addConformanceRefs(ArrayRef conformances); SmallVector addConformanceRefs(ArrayRef conformances); /// Records the use of the given SILLayout. SILLayoutID addSILLayoutRef(const SILLayout *layout); /// Records the module containing \p DC. /// /// The module's name will be scheduled for serialization if necessary. This /// may not be exactly the same as the name of the module containing DC; /// instead, it will match the containing file's "exported module name". /// /// \param ignoreExport When true, register the real module name, /// ignoring exported_as definitions. /// \returns The ID for the identifier for the module's name, or one of the /// special module codes defined above. /// \see FileUnit::getExportedModuleName IdentifierID addContainingModuleRef(const DeclContext *DC, bool ignoreExport); /// Records the module \m. IdentifierID addModuleRef(const ModuleDecl *m); /// Write a SILLayout. void writeASTBlockEntity(const SILLayout *layout); /// Adds an encoding of the given list of generic requirements to /// the given list of values. void serializeGenericRequirements(ArrayRef requirements, SmallVectorImpl &scratch); /// Writes a protocol's requirement signature, consisting of a list of /// generic requirements and a list of protocol typealias records. void writeRequirementSignature(const RequirementSignature &requirementSig); /// Writes a protocol's associated type table. void writeAssociatedTypes(ArrayRef assocTypes); /// Writes a protocol's primary associated type table. void writePrimaryAssociatedTypes(ArrayRef assocTypes); bool allowCompilerErrors() const; private: /// If the declaration is invalid, records that an error occurred and returns /// true if the decl should be skipped. bool skipDeclIfInvalid(const Decl *decl); /// If the type is invalid, records that an error occurred and returns /// true if the type should be skipped. bool skipTypeIfInvalid(Type ty, TypeRepr *tyRepr); /// If the type is invalid, records that an error occurred and returns /// true if the type should be skipped. bool skipTypeIfInvalid(Type ty, SourceLoc loc); }; } // end namespace serialization } // end namespace swift #endif