//===--- Serialization.h - Read and write Swift modules ---------*- C++ -*-===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // // This file defines the Serializer interface. // //===----------------------------------------------------------------------===// #ifndef SWIFT_SERIALIZATION_SERIALIZATION_H #define SWIFT_SERIALIZATION_SERIALIZATION_H #include "swift/Serialization/ModuleFormat.h" #include "swift/Serialization/SerializationOptions.h" #include "swift/Subsystems.h" #include "swift/AST/Identifier.h" #include "swift/Basic/LLVM.h" #include "llvm/ADT/MapVector.h" #include #include #include namespace swift { class SILModule; namespace serialization { typedef ArrayRef FilenamesTy; class Serializer { 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; public: /// Stores a declaration or a type to be written to the AST file. /// /// Convenience wrapper around a PointerUnion. class DeclTypeUnion { using DataTy = llvm::PointerUnion; DataTy Data; explicit DeclTypeUnion(const void *val) : Data(DataTy::getFromOpaqueValue(const_cast(val))) {} public: /*implicit*/ DeclTypeUnion(const Decl *d) : Data(d) { } /*implicit*/ DeclTypeUnion(Type ty) : Data(ty) { } bool isDecl() const { return Data.is(); } bool isType() const { return Data.is(); } Type getType() const { return Data.get(); } const Decl *getDecl() const { return Data.get(); } const void *getOpaqueValue() const { return Data.getOpaqueValue(); } static DeclTypeUnion getFromOpaqueValue(void *opaqueVal) { return DeclTypeUnion(opaqueVal); } bool operator==(const DeclTypeUnion &other) const { return Data == other.Data; } }; // FIXME: This should be a PointerIntPair, but there's a bug in // PointerIntPair when the number of free bits is greater than 32. using DeclIDAndForce = std::pair; private: /// A map from Types and Decls to their serialized IDs. llvm::DenseMap DeclAndTypeIDs; /// A map from Identifiers to their serialized IDs. llvm::DenseMap IdentifierIDs; /// A map from DeclContexts to their serialized IDs. llvm::DenseMap DeclContextIDs; /// A map from local DeclContexts to their serialized IDs. llvm::DenseMap LocalDeclContextIDs; /// A map from generic parameter lists to the decls they come from. llvm::DenseMap GenericContexts; // A map from NormalProtocolConformances to their serialized IDs. llvm::DenseMap NormalConformances; public: using DeclTableData = SmallVector, 4>; /// The in-memory representation of what will eventually be an on-disk hash /// table. using DeclTable = llvm::MapVector; /// Returns the declaration the given generic parameter list is associated /// with. const Decl *getGenericContext(const GenericParamList *paramList); 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::DenseMap; private: /// A map from identifiers to methods and properties with the given name. /// /// This is used for id-style lookup. DeclTable ClassMembersByName; /// The queue of types and decls that need to be serialized. /// /// This is a queue and not simply a vector because serializing one /// decl-or-type might trigger the serialization of another one. std::queue DeclsAndTypesToWrite; /// DeclContexts that need to be serialized. std::queue DeclContextsToWrite; /// Local DeclContexts that need to be serialized. std::queue LocalDeclContextsToWrite; /// NormalProtocolConformances that need to be serialized. std::queue NormalConformancesToWrite; /// All identifiers that need to be serialized. std::vector IdentifiersToWrite; /// 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 offset of each Decl in the bitstream, indexed by DeclID. std::vector DeclOffsets; /// The offset of each Type in the bitstream, indexed by TypeID. std::vector TypeOffsets; /// The offset of each DeclContext in the bitstream, indexed by DeclContextID std::vector DeclContextOffsets; /// The offset of each localDeclContext in the bitstream, /// indexed by DeclContextID std::vector LocalDeclContextOffsets; /// The offset of each Identifier in the identifier data block, indexed by /// IdentifierID. std::vector IdentifierOffsets; /// The offset of each NormalProtocolConformance in the bitstream, indexed by /// NormalConformanceID. std::vector NormalConformanceOffsets; /// The decls that adopt compiler-known protocols. SmallVector KnownProtocolAdopters[NumKnownProtocols]; /// The last assigned DeclID for decls from this module. uint32_t /*DeclID*/ LastDeclID = 0; /// The last assigned DeclContextID for decl contexts from this module. uint32_t /*DeclContextID*/ LastDeclContextID = 0; /// The last assigned DeclContextID for local decl contexts from this module. uint32_t /*DeclContextID*/ LastLocalDeclContextID = 0; /// The last assigned NormalConformanceID for decl contexts from this module. uint32_t /*NormalConformanceID*/ LastNormalConformanceID = 0; /// The last assigned DeclID for types from this module. uint32_t /*TypeID*/ LastTypeID = 0; /// The last assigned IdentifierID for types from this module. /// /// Note that special module IDs must not be valid IdentifierIDs, except that /// 0 will always represent the empty identifier. uint32_t /*IdentifierID*/ LastIdentifierID = serialization::NUM_SPECIAL_MODULES - 1; /// Returns the record code for serializing the given vector of offsets. /// /// This allows the offset-serialization code to be generic over all kinds /// of offsets. unsigned getOffsetRecordCode(const std::vector &values) { if (&values == &DeclOffsets) return index_block::DECL_OFFSETS; if (&values == &TypeOffsets) return index_block::TYPE_OFFSETS; if (&values == &IdentifierOffsets) return index_block::IDENTIFIER_OFFSETS; if (&values == &DeclContextOffsets) return index_block::DECL_CONTEXT_OFFSETS; if (&values == &LocalDeclContextOffsets) return index_block::LOCAL_DECL_CONTEXT_OFFSETS; if (&values == &NormalConformanceOffsets) return index_block::NORMAL_CONFORMANCE_OFFSETS; llvm_unreachable("unknown offset kind"); } /// Writes the BLOCKINFO block for the serialized module file. void writeBlockInfoBlock(); /// Writes the BLOCKINFO block for the module documentation file. void writeDocBlockInfoBlock(); /// Writes the Swift module file header and name, plus metadata determining /// if the module can be loaded. void writeHeader(const SerializationOptions &options = {}); /// Writes the Swift doc module file header and name. void writeDocHeader(); /// Writes the dependencies used to build this module: its imported /// modules and its source files. void writeInputBlock(const SerializationOptions &options); void writeParameterList(const ParameterList *PL); /// Writes the given pattern, recursively. void writePattern(const Pattern *pattern); /// Writes a set of generic requirements. void writeRequirements(ArrayRef requirements); /// Writes a list of protocol conformances. void writeConformances(ArrayRef conformances, const std::array &abbrCodes); /// Writes a list of protocol conformances. void writeConformances(ArrayRef conformances, const std::array &abbrCodes); /// Writes an array of members for a decl context. /// /// \param members The decls within the context /// \param isClass True if the context could be a class context (class, /// class extension, or protocol). void writeMembers(DeclRange members, bool isClass); /// Check if a decl is cross-referenced. bool isDeclXRef(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 out a declaration attribute. void writeDeclAttribute(const DeclAttribute *DA); /// Writes out a foreign error convention. void writeForeignErrorConvention(const ForeignErrorConvention &fec); /// Writes the given decl. void writeDecl(const Decl *D); /// Writes the given decl context. void writeDeclContext(const DeclContext *DC); /// Write a DeclContext as a local DeclContext at the current offset. void writeLocalDeclContext(const DeclContext *DC); /// Write the components of a PatternBindingInitializer as a local context. void writePatternBindingInitializer(PatternBindingDecl *binding); /// 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 writeType(Type ty); /// 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 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. void writeAllIdentifiers(); /// Writes the offsets for decls or types. void writeOffsets(const index_block::OffsetsLayout &Offsets, const std::vector &values); /// Serializes all transparent SIL functions in the SILModule. void writeSIL(const SILModule *M, bool serializeAllSIL); /// Top-level entry point for serializing a module. void writeAST(ModuleOrSourceFile DC); void writeToStream(raw_ostream &os); template Serializer(const unsigned char (&signature)[N], ModuleOrSourceFile DC); public: /// Serialize a module to the given stream. static void writeToStream(raw_ostream &os, ModuleOrSourceFile DC, const SILModule *M, const SerializationOptions &options); /// Serialize module documentation to the given stream. static void writeDocToStream(raw_ostream &os, ModuleOrSourceFile DC, StringRef GroupInfoPath, ASTContext &Ctx); /// 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 Identifier. /// /// The Identifier will be scheduled for serialization if necessary. /// /// \returns The ID for the given Identifier in this module. IdentifierID addIdentifierRef(Identifier ident); /// 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 forceSerialization = 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. DeclContextID addLocalDeclContextRef(const DeclContext *DC); /// Records the use of the given normal protocol conformance. /// /// The normal protocol conformance will be scheduled for /// serialization if necessary. /// /// \returns The ID for the given conformance in this module. NormalConformanceID addConformanceRef( const NormalProtocolConformance *conformance); /// Records the use of the given module. /// /// The module's name will be scheduled for serialization if necessary. /// /// \returns The ID for the identifier for the module's name, or one of the /// special module codes defined above. IdentifierID addModuleRef(const ModuleDecl *M); /// Writes a list of generic substitutions. abbrCode is needed to support /// usage out of decl block. void writeSubstitutions(ArrayRef substitutions, const std::array &abbrCodes); /// Write a normal protocol conformance. void writeNormalConformance(const NormalProtocolConformance *conformance); /// Writes a protocol conformance. void writeConformance(ProtocolConformanceRef conformance, const std::array &abbrCodes); /// Writes a protocol conformance. void writeConformance(ProtocolConformance *conformance, const std::array &abbrCodes); /// Writes a generic parameter list. bool writeGenericParams(const GenericParamList *genericParams, const std::array &abbrCodes); }; } // end namespace serialization } // end namespace swift #endif