mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
SubstitutionList is going to be a more compact representation of a SubstitutionMap, suitable for inline allocation inside another object. For now, it's just a typedef for ArrayRef<Substitution>.
4463 lines
159 KiB
C++
4463 lines
159 KiB
C++
//===--- 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/AST.h"
|
|
#include "swift/AST/ASTWalker.h"
|
|
#include "swift/AST/DiagnosticsCommon.h"
|
|
#include "swift/AST/ForeignErrorConvention.h"
|
|
#include "swift/AST/GenericEnvironment.h"
|
|
#include "swift/AST/Initializer.h"
|
|
#include "swift/AST/LinkLibrary.h"
|
|
#include "swift/AST/Mangle.h"
|
|
#include "swift/AST/ProtocolConformance.h"
|
|
#include "swift/AST/ASTMangler.h"
|
|
#include "swift/AST/RawComment.h"
|
|
#include "swift/AST/USRGeneration.h"
|
|
#include "swift/Basic/Dwarf.h"
|
|
#include "swift/Basic/Fallthrough.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/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 <vector>
|
|
|
|
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<uint32_t>;
|
|
using PtrIntInfo = std::numeric_limits<uintptr_t>;
|
|
using DeclIDTraits = llvm::PointerLikeTypeTraits<DeclID>;
|
|
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<unsigned, unsigned> 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<little> writer(out);
|
|
writer.write<uint16_t>(keyLength);
|
|
writer.write<uint16_t>(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<little> writer(out);
|
|
for (auto entry : data) {
|
|
writer.write<uint8_t>(entry.first);
|
|
writer.write<uint32_t>(entry.second);
|
|
}
|
|
}
|
|
};
|
|
|
|
class LocalDeclTableInfo {
|
|
public:
|
|
using key_type = std::string;
|
|
using key_type_ref = StringRef;
|
|
using data_type = std::pair<DeclID, unsigned>; // 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<unsigned, unsigned> 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<little> writer(out);
|
|
writer.write<uint16_t>(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<little> writer(out);
|
|
writer.write<uint32_t>(data.first);
|
|
writer.write<unsigned>(data.second);
|
|
}
|
|
};
|
|
|
|
using LocalTypeHashTableGenerator =
|
|
llvm::OnDiskChainedHashTableGenerator<LocalDeclTableInfo>;
|
|
|
|
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<unsigned, unsigned> 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<little> writer(out);
|
|
writer.write<uint16_t>(keyLength);
|
|
writer.write<uint16_t>(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<little> writer(out);
|
|
for (auto entry : data) {
|
|
writer.write<uint32_t>(entry.first);
|
|
writer.write<uint32_t>(entry.second);
|
|
}
|
|
}
|
|
};
|
|
} // end anonymous namespace
|
|
|
|
namespace llvm {
|
|
template<> struct DenseMapInfo<Serializer::DeclTypeUnion> {
|
|
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<const void *>::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<ModuleDecl *>())
|
|
return M;
|
|
return DC.get<SourceFile *>()->getParentModule();
|
|
}
|
|
|
|
static ASTContext &getContext(ModuleOrSourceFile DC) {
|
|
return getModule(DC)->getASTContext();
|
|
}
|
|
|
|
static bool shouldSerializeAsLocalContext(const DeclContext *DC) {
|
|
return DC->isLocalContext() && !isa<AbstractFunctionDecl>(DC) &&
|
|
!isa<SubscriptDecl>(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<GenericTypeDecl>(DC);
|
|
case DeclContextKind::ExtensionDecl:
|
|
return cast<ExtensionDecl>(DC);
|
|
case DeclContextKind::TopLevelCodeDecl:
|
|
llvm_unreachable("shouldn't serialize the main module");
|
|
case DeclContextKind::AbstractFunctionDecl:
|
|
return cast<AbstractFunctionDecl>(DC);
|
|
case DeclContextKind::SubscriptDecl:
|
|
return cast<SubscriptDecl>(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) {
|
|
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<ValueDecl>(D) || isa<OperatorDecl>(D) ||
|
|
isa<PrecedenceGroupDecl>(D)) &&
|
|
"cannot cross-reference this decl");
|
|
|
|
// Record any generic parameters that come from this decl, so that we can use
|
|
// the decl to refer to the parameters later.
|
|
const GenericParamList *paramList = nullptr;
|
|
if (auto fn = dyn_cast<AbstractFunctionDecl>(D))
|
|
paramList = fn->getGenericParams();
|
|
else if (auto nominal = dyn_cast<NominalTypeDecl>(D))
|
|
paramList = nominal->getGenericParams();
|
|
else if (auto ext = dyn_cast<ExtensionDecl>(D))
|
|
paramList = ext->getGenericParams();
|
|
if (paramList)
|
|
GenericContexts[paramList] = D;
|
|
|
|
id = { ++LastDeclID, forceSerialization };
|
|
DeclsAndTypesToWrite.push(D);
|
|
return id.first;
|
|
}
|
|
|
|
TypeID Serializer::addTypeRef(Type ty) {
|
|
if (!ty)
|
|
return 0;
|
|
|
|
assert(!ty->hasError() && "Serializing error type");
|
|
|
|
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<ClangImporter *>(
|
|
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;
|
|
}
|
|
|
|
const Decl *Serializer::getGenericContext(const GenericParamList *paramList) {
|
|
auto contextDecl = GenericContexts.lookup(paramList);
|
|
return contextDecl;
|
|
}
|
|
|
|
/// Record the name of a block.
|
|
static void emitBlockID(llvm::BitstreamWriter &out, unsigned ID,
|
|
StringRef name,
|
|
SmallVectorImpl<unsigned char> &nameBuffer) {
|
|
SmallVector<unsigned, 1> 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<unsigned char> &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<unsigned char, 64> 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(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<unsigned char, 64> 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 << '/' << version::getSwiftFullVersion(
|
|
M->getASTContext().LangOpts.EffectiveLanguageVersion);
|
|
Metadata.emit(ScratchRecord,
|
|
VERSION_MAJOR, VERSION_MINOR, shortVersionStringLength,
|
|
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);
|
|
for (const std::string &arg : options.ExtraClangOptions) {
|
|
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,
|
|
version::getSwiftFullVersion(
|
|
LangOpts.EffectiveLanguageVersion));
|
|
|
|
Target.emit(ScratchRecord, LangOpts.Target.str());
|
|
}
|
|
}
|
|
|
|
static void
|
|
removeDuplicateImports(SmallVectorImpl<ModuleDecl::ImportedModule> &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<Identifier, SourceLoc>;
|
|
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<FileUnit *> files = import.second->getFiles();
|
|
if (auto clangModule = dyn_cast<ClangModuleUnit>(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<StringRef, 4> 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 &path : searchPathOpts.FrameworkSearchPaths)
|
|
SearchPath.emit(ScratchRecord, /*framework=*/true, path);
|
|
for (auto &path : searchPathOpts.ImportSearchPaths)
|
|
SearchPath.emit(ScratchRecord, /*framework=*/false, path);
|
|
}
|
|
|
|
// FIXME: Having to deal with private imports as a superset of public imports
|
|
// is inefficient.
|
|
SmallVector<ModuleDecl::ImportedModule, 8> publicImports;
|
|
SmallVector<ModuleDecl::ImportedModule, 8> allImports;
|
|
for (auto file : M->getFiles()) {
|
|
file->getImportedModules(publicImports, ModuleDecl::ImportFilter::Public);
|
|
file->getImportedModules(allImports, ModuleDecl::ImportFilter::All);
|
|
}
|
|
|
|
llvm::SmallSet<ModuleDecl::ImportedModule, 8, ModuleDecl::OrderImportedModules>
|
|
publicImportSet;
|
|
publicImportSet.insert(publicImports.begin(), publicImports.end());
|
|
|
|
removeDuplicateImports(allImports);
|
|
auto clangImporter =
|
|
static_cast<ClangImporter *>(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<uint8_t>(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<ParenPattern>(pattern)->getSubPattern(), owningDC);
|
|
break;
|
|
}
|
|
case PatternKind::Tuple: {
|
|
auto tuple = cast<TuplePattern>(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<NamedPattern>(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<TypedPattern>(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<VarPattern>(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<Requirement> requirements,
|
|
const std::array<unsigned, 256> &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();
|
|
}
|
|
LayoutRequirementLayout::emitRecord(
|
|
Out, ScratchRecord, layoutReqAbbrCode, (unsigned)layout->getKind(),
|
|
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<uint64_t, 4> 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<GenericTypeParamType>();
|
|
}
|
|
|
|
rawParamIDs.push_back(addTypeRef(paramTy));
|
|
rawParamIDs.push_back(addTypeRef(env->mapTypeIntoContext(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");
|
|
auto layoutID = foundLayoutID->second;
|
|
assert(layoutID - 1 == SILLayoutOffsets.size());
|
|
SILLayoutOffsets.push_back(Out.GetCurrentBitNo());
|
|
|
|
SmallVector<unsigned, 16> 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<DeclID, 32> data;
|
|
unsigned numValueWitnesses = 0;
|
|
unsigned numTypeWitnesses = 0;
|
|
|
|
// Collect the set of protocols inherited by this conformance.
|
|
SmallVector<ProtocolDecl *, 8> inheritedProtos;
|
|
for (auto inheritedMapping : conformance->getInheritedConformances()) {
|
|
inheritedProtos.push_back(inheritedMapping.first);
|
|
}
|
|
|
|
// Sort the protocols so that we get a deterministic ordering.
|
|
llvm::array_pod_sort(inheritedProtos.begin(), inheritedProtos.end(),
|
|
ProtocolType::compareProtocols);
|
|
|
|
conformance->forEachValueWitness(nullptr,
|
|
[&](ValueDecl *req, Witness witness) {
|
|
data.push_back(addDeclRef(req));
|
|
data.push_back(addDeclRef(witness.getDecl()));
|
|
assert(witness.getDecl() || req->getAttrs().hasAttribute<OptionalAttr>()
|
|
|| 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));
|
|
|
|
// Mapping from the requirement's interface types to the interface
|
|
// types of the synthetic environment.
|
|
auto reqSignature =
|
|
req->getInnermostDeclContext()->getGenericSignatureOfContext();
|
|
const auto &reqToSyntheticMap = witness.getRequirementToSyntheticMap();
|
|
for (auto reqGP : reqSignature->getGenericParams()) {
|
|
auto canonicalGP =
|
|
cast<GenericTypeParamType>(reqGP->getCanonicalType());
|
|
data.push_back(
|
|
addTypeRef(Type(canonicalGP).subst(reqToSyntheticMap)));
|
|
auto conformances = reqToSyntheticMap.getConformances(canonicalGP);
|
|
data.push_back(conformances.size());
|
|
// Conformances come at the end.
|
|
}
|
|
|
|
// Requirements come at the end.
|
|
} else {
|
|
data.push_back(0);
|
|
}
|
|
|
|
data.push_back(witness.getSubstitutions().size());
|
|
++numValueWitnesses;
|
|
});
|
|
|
|
conformance->forEachTypeWitness(/*resolver=*/nullptr,
|
|
[&](AssociatedTypeDecl *assocType,
|
|
const Substitution &witness,
|
|
TypeDecl *typeDecl) {
|
|
data.push_back(addDeclRef(assocType));
|
|
data.push_back(addDeclRef(typeDecl));
|
|
// The substitution record is serialized later.
|
|
++numTypeWitnesses;
|
|
return false;
|
|
});
|
|
|
|
unsigned numInheritedConformances = inheritedProtos.size();
|
|
unsigned abbrCode
|
|
= DeclTypeAbbrCodes[NormalProtocolConformanceLayout::Code];
|
|
auto ownerID = addDeclContextRef(conformance->getDeclContext());
|
|
NormalProtocolConformanceLayout::emitRecord(Out, ScratchRecord, abbrCode,
|
|
addDeclRef(protocol), ownerID,
|
|
numValueWitnesses,
|
|
numTypeWitnesses,
|
|
numInheritedConformances,
|
|
data);
|
|
|
|
// Write inherited conformances.
|
|
for (auto inheritedProto : inheritedProtos) {
|
|
writeConformance(conformance->getInheritedConformance(inheritedProto),
|
|
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 conformances for the requirement-to-synthetic environment map.
|
|
auto reqSignature =
|
|
req->getInnermostDeclContext()->getGenericSignatureOfContext();
|
|
const auto &reqToSyntheticMap = witness.getRequirementToSyntheticMap();
|
|
for (auto reqGP : reqSignature->getGenericParams()) {
|
|
auto canonicalGP =
|
|
cast<GenericTypeParamType>(reqGP->getCanonicalType());
|
|
auto conformances = reqToSyntheticMap.getConformances(canonicalGP);
|
|
for (auto conformance : conformances) {
|
|
writeConformance(conformance, DeclTypeAbbrCodes);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Write the witness substitutions.
|
|
writeSubstitutions(witness.getSubstitutions(),
|
|
DeclTypeAbbrCodes,
|
|
witness.requiresSubstitution()
|
|
? witness.getSyntheticEnvironment()
|
|
: nullptr);
|
|
});
|
|
|
|
conformance->forEachTypeWitness(/*resolver=*/nullptr,
|
|
[&](AssociatedTypeDecl *assocType,
|
|
const Substitution &witness,
|
|
TypeDecl *typeDecl) {
|
|
writeSubstitutions(witness, DeclTypeAbbrCodes);
|
|
return false;
|
|
});
|
|
}
|
|
|
|
void
|
|
Serializer::writeConformance(ProtocolConformance *conformance,
|
|
const std::array<unsigned, 256> &abbrCodes,
|
|
GenericEnvironment *genericEnv) {
|
|
writeConformance(ProtocolConformanceRef(conformance), abbrCodes, genericEnv);
|
|
}
|
|
|
|
void
|
|
Serializer::writeConformance(ProtocolConformanceRef conformanceRef,
|
|
const std::array<unsigned, 256> &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<NormalProtocolConformance>(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<SpecializedProtocolConformance>(conformance);
|
|
auto substitutions = conf->getGenericSubstitutions();
|
|
unsigned abbrCode = abbrCodes[SpecializedProtocolConformanceLayout::Code];
|
|
auto type = conf->getType();
|
|
if (genericEnv)
|
|
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<InheritedProtocolConformance>(conformance);
|
|
unsigned abbrCode
|
|
= abbrCodes[InheritedProtocolConformanceLayout::Code];
|
|
|
|
auto type = conf->getType();
|
|
if (genericEnv)
|
|
type = genericEnv->mapTypeOutOfContext(type);
|
|
|
|
InheritedProtocolConformanceLayout::emitRecord(
|
|
Out, ScratchRecord, abbrCode, addTypeRef(type));
|
|
|
|
writeConformance(conf->getInheritedConformance(), abbrCodes, genericEnv);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
Serializer::writeConformances(ArrayRef<ProtocolConformanceRef> conformances,
|
|
const std::array<unsigned, 256> &abbrCodes) {
|
|
using namespace decls_block;
|
|
|
|
for (auto conformance : conformances)
|
|
writeConformance(conformance, abbrCodes);
|
|
}
|
|
|
|
void
|
|
Serializer::writeConformances(ArrayRef<ProtocolConformance*> conformances,
|
|
const std::array<unsigned, 256> &abbrCodes) {
|
|
using namespace decls_block;
|
|
|
|
for (auto conformance : conformances)
|
|
writeConformance(conformance, abbrCodes);
|
|
}
|
|
|
|
void
|
|
Serializer::writeSubstitutions(SubstitutionList substitutions,
|
|
const std::array<unsigned, 256> &abbrCodes,
|
|
GenericEnvironment *genericEnv) {
|
|
using namespace decls_block;
|
|
auto abbrCode = abbrCodes[BoundGenericSubstitutionLayout::Code];
|
|
|
|
for (auto &sub : substitutions) {
|
|
auto replacementType = sub.getReplacement();
|
|
if (genericEnv) {
|
|
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<uint8_t>(serialization::OptionalTypeKind::None);
|
|
case swift::OTK_Optional:
|
|
return static_cast<uint8_t>(serialization::OptionalTypeKind::Optional);
|
|
case swift::OTK_ImplicitlyUnwrappedOptional:
|
|
return static_cast<uint8_t>(
|
|
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<DeclID, 16> memberIDs;
|
|
for (auto member : members) {
|
|
if (!shouldSerializeMember(member))
|
|
continue;
|
|
|
|
DeclID memberID = addDeclRef(member);
|
|
memberIDs.push_back(memberID);
|
|
|
|
if (isClass) {
|
|
if (auto VD = dyn_cast<ValueDecl>(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<unsigned, 256> &abbrCodes) {
|
|
using namespace decls_block;
|
|
|
|
SmallVector<DeclID, 16> witnessIDs;
|
|
|
|
unsigned abbrCode = abbrCodes[DefaultWitnessTableLayout::Code];
|
|
for (auto member : proto->getMembers()) {
|
|
if (auto *value = dyn_cast<ValueDecl>(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<FileUnit>(DC)->getParentModule();
|
|
SWIFT_FALLTHROUGH;
|
|
|
|
case DeclContextKind::Module:
|
|
abbrCode = DeclTypeAbbrCodes[XRefLayout::Code];
|
|
XRefLayout::emitRecord(Out, ScratchRecord, abbrCode,
|
|
addModuleRef(cast<ModuleDecl>(DC)), pathLen);
|
|
break;
|
|
|
|
case DeclContextKind::GenericTypeDecl: {
|
|
writeCrossReference(DC->getParent(), pathLen + 1);
|
|
|
|
auto generic = cast<GenericTypeDecl>(DC);
|
|
abbrCode = DeclTypeAbbrCodes[XRefTypePathPieceLayout::Code];
|
|
XRefTypePathPieceLayout::emitRecord(Out, ScratchRecord, abbrCode,
|
|
addIdentifierRef(generic->getName()),
|
|
false);
|
|
break;
|
|
}
|
|
|
|
case DeclContextKind::ExtensionDecl: {
|
|
auto ext = cast<ExtensionDecl>(DC);
|
|
Type baseTy = ext->getExtendedType();
|
|
writeCrossReference(baseTy->getAnyNominal(), pathLen + 1);
|
|
|
|
abbrCode = DeclTypeAbbrCodes[XRefExtensionPathPieceLayout::Code];
|
|
SmallVector<TypeID, 4> 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<SubscriptDecl>(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<FuncDecl>(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<AbstractFunctionDecl>(DC);
|
|
writeCrossReference(DC->getParent(), pathLen + 1 + fn->isOperator());
|
|
|
|
Type ty = fn->getInterfaceType()->getCanonicalType();
|
|
|
|
if (auto ctor = dyn_cast<ConstructorDecl>(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<FuncDecl>(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<OperatorDecl>(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<PrecedenceGroupDecl>(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<AbstractFunctionDecl>(D)) {
|
|
// Functions are special because they might be operators.
|
|
writeCrossReference(fn, 0);
|
|
return;
|
|
}
|
|
|
|
writeCrossReference(D->getDeclContext());
|
|
|
|
if (auto genericParam = dyn_cast<GenericTypeParamDecl>(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;
|
|
}
|
|
|
|
if (auto type = dyn_cast<TypeDecl>(D)) {
|
|
abbrCode = DeclTypeAbbrCodes[XRefTypePathPieceLayout::Code];
|
|
XRefTypePathPieceLayout::emitRecord(Out, ScratchRecord, abbrCode,
|
|
addIdentifierRef(type->getName()),
|
|
isa<ProtocolDecl>(
|
|
type->getDeclContext()));
|
|
return;
|
|
}
|
|
|
|
auto val = cast<ValueDecl>(D);
|
|
auto ty = val->getInterfaceType()->getCanonicalType();
|
|
bool isProtocolExt = D->getDeclContext()->getAsProtocolExtensionContext();
|
|
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<uint8_t>(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<Serializer::DeclTypeUnion,
|
|
Serializer::DeclIDAndForce> &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<unsigned> &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:
|
|
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<SILGenNameAttr>(DA);
|
|
auto abbrCode = DeclTypeAbbrCodes[SILGenNameDeclAttrLayout::Code];
|
|
SILGenNameDeclAttrLayout::emitRecord(Out, ScratchRecord, abbrCode,
|
|
theAttr->isImplicit(),
|
|
theAttr->Name);
|
|
return;
|
|
}
|
|
|
|
case DAK_CDecl: {
|
|
auto *theAttr = cast<CDeclAttr>(DA);
|
|
auto abbrCode = DeclTypeAbbrCodes[CDeclDeclAttrLayout::Code];
|
|
CDeclDeclAttrLayout::emitRecord(Out, ScratchRecord, abbrCode,
|
|
theAttr->isImplicit(),
|
|
theAttr->Name);
|
|
return;
|
|
}
|
|
|
|
case DAK_Alignment: {
|
|
auto *theAlignment = cast<AlignmentAttr>(DA);
|
|
auto abbrCode = DeclTypeAbbrCodes[AlignmentDeclAttrLayout::Code];
|
|
AlignmentDeclAttrLayout::emitRecord(Out, ScratchRecord, abbrCode,
|
|
theAlignment->isImplicit(),
|
|
theAlignment->Value);
|
|
return;
|
|
}
|
|
|
|
case DAK_SwiftNativeObjCRuntimeBase: {
|
|
auto *theBase = cast<SwiftNativeObjCRuntimeBaseAttr>(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<SemanticsAttr>(DA);
|
|
auto abbrCode = DeclTypeAbbrCodes[SemanticsDeclAttrLayout::Code];
|
|
SemanticsDeclAttrLayout::emitRecord(Out, ScratchRecord, abbrCode,
|
|
theAttr->isImplicit(),
|
|
theAttr->Value);
|
|
return;
|
|
}
|
|
|
|
case DAK_Inline: {
|
|
auto *theAttr = cast<InlineAttr>(DA);
|
|
auto abbrCode = DeclTypeAbbrCodes[InlineDeclAttrLayout::Code];
|
|
InlineDeclAttrLayout::emitRecord(Out, ScratchRecord, abbrCode,
|
|
(unsigned)theAttr->getKind());
|
|
return;
|
|
}
|
|
|
|
case DAK_Effects: {
|
|
auto *theAttr = cast<EffectsAttr>(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<AvailableAttr>(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<unsigned>(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<AutoClosureAttr>(DA);
|
|
auto abbrCode = DeclTypeAbbrCodes[AutoClosureDeclAttrLayout::Code];
|
|
AutoClosureDeclAttrLayout::emitRecord(Out, ScratchRecord, abbrCode,
|
|
theAttr->isImplicit(),
|
|
theAttr->isEscaping());
|
|
return;
|
|
}
|
|
|
|
case DAK_ObjC: {
|
|
auto *theAttr = cast<ObjCAttr>(DA);
|
|
SmallVector<IdentifierID, 4> 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->isNameImplicit(), numArgs, pieces);
|
|
return;
|
|
}
|
|
|
|
case DAK_Specialize: {
|
|
auto abbrCode = DeclTypeAbbrCodes[SpecializeDeclAttrLayout::Code];
|
|
auto SA = cast<SpecializeAttr>(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<FileUnit>(topLevel)) {
|
|
assert(isa<GenericTypeParamDecl>(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<AbstractClosureExpr>(DC);
|
|
writeAbstractClosureExpr(ACE->getParent(), ACE->getType(),
|
|
ACE->isImplicit(), ACE->getDiscriminator());
|
|
break;
|
|
}
|
|
|
|
case DeclContextKind::Initializer: {
|
|
if (auto PBI = dyn_cast<PatternBindingInitializer>(DC)) {
|
|
writePatternBindingInitializer(PBI->getBinding(), PBI->getBindingIndex());
|
|
} else if (auto DAI = dyn_cast<DefaultArgumentInitializer>(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<SerializedLocalDeclContext>(DC);
|
|
switch (local->getLocalDeclContextKind()) {
|
|
case LocalDeclContextKind::AbstractClosure: {
|
|
auto SACE = cast<SerializedAbstractClosureExpr>(local);
|
|
writeAbstractClosureExpr(SACE->getParent(), SACE->getType(),
|
|
SACE->isImplicit(), SACE->getDiscriminator());
|
|
return;
|
|
}
|
|
case LocalDeclContextKind::DefaultArgumentInitializer: {
|
|
auto DAI = cast<SerializedDefaultArgumentInitializer>(local);
|
|
writeDefaultArgumentInitializer(DAI->getParent(), DAI->getIndex());
|
|
return;
|
|
}
|
|
case LocalDeclContextKind::PatternBindingInitializer: {
|
|
auto PBI = cast<SerializedPatternBindingInitializer>(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<uint8_t>(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<ValueDecl>(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<FileUnit>(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<ExtensionDecl>(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<TypeID, 8> 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<ClassDecl>(baseNominal) ||
|
|
isa<ProtocolDecl>(baseNominal);
|
|
}
|
|
|
|
writeGenericParams(extension->getGenericParams());
|
|
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<PatternBindingDecl>(D);
|
|
verifyAttrSerializable(binding);
|
|
|
|
auto contextID = addDeclContextRef(binding->getDeclContext());
|
|
SmallVector<uint64_t, 2> 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<PrecedenceGroupDecl>(D);
|
|
verifyAttrSerializable(group);
|
|
|
|
auto contextID = addDeclContextRef(group->getDeclContext());
|
|
auto nameID = addIdentifierRef(group->getName());
|
|
auto associativity = getRawStableAssociativity(group->getAssociativity());
|
|
|
|
SmallVector<DeclID, 8> 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<InfixOperatorDecl>(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<PrefixOperatorDecl>(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<PostfixOperatorDecl>(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<TypeAliasDecl>(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),
|
|
addTypeRef(typeAlias->getInterfaceType()),
|
|
typeAlias->isImplicit(),
|
|
addGenericEnvironmentRef(
|
|
typeAlias->getGenericEnvironment()),
|
|
rawAccessLevel);
|
|
writeGenericParams(typeAlias->getGenericParams());
|
|
break;
|
|
}
|
|
|
|
case DeclKind::GenericTypeParam: {
|
|
auto genericParam = cast<GenericTypeParamDecl>(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<AssociatedTypeDecl>(D);
|
|
verifyAttrSerializable(assocType);
|
|
|
|
auto contextID = addDeclContextRef(assocType->getDeclContext());
|
|
|
|
SmallVector<TypeID, 4> 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<StructDecl>(D);
|
|
verifyAttrSerializable(theStruct);
|
|
|
|
auto contextID = addDeclContextRef(theStruct->getDeclContext());
|
|
|
|
auto conformances = theStruct->getLocalConformances(
|
|
ConformanceLookupKind::All,
|
|
nullptr, /*sorted=*/true);
|
|
|
|
SmallVector<TypeID, 4> 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<EnumDecl>(D);
|
|
verifyAttrSerializable(theEnum);
|
|
|
|
auto contextID = addDeclContextRef(theEnum->getDeclContext());
|
|
|
|
auto conformances = theEnum->getLocalConformances(
|
|
ConformanceLookupKind::All,
|
|
nullptr, /*sorted=*/true);
|
|
|
|
SmallVector<TypeID, 4> 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<ClassDecl>(D);
|
|
verifyAttrSerializable(theClass);
|
|
assert(!theClass->isForeign());
|
|
|
|
auto contextID = addDeclContextRef(theClass->getDeclContext());
|
|
|
|
auto conformances = theClass->getLocalConformances(
|
|
ConformanceLookupKind::All,
|
|
nullptr, /*sorted=*/true);
|
|
|
|
SmallVector<TypeID, 4> 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<ProtocolDecl>(D);
|
|
verifyAttrSerializable(proto);
|
|
|
|
auto contextID = addDeclContextRef(proto->getDeclContext());
|
|
|
|
SmallVector<DeclID, 8> protocolsAndInherited;
|
|
for (auto proto : proto->getInheritedProtocols(nullptr))
|
|
protocolsAndInherited.push_back(addDeclRef(proto));
|
|
unsigned numProtocols = protocolsAndInherited.size();
|
|
for (auto inherited : proto->getInherited())
|
|
protocolsAndInherited.push_back(addTypeRef(inherited.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<ProtocolDecl *>(proto)
|
|
->requiresClass(),
|
|
proto->isObjC(),
|
|
addGenericEnvironmentRef(
|
|
proto->getGenericEnvironment()),
|
|
rawAccessLevel,
|
|
numProtocols,
|
|
protocolsAndInherited);
|
|
|
|
writeGenericParams(proto->getGenericParams());
|
|
writeMembers(proto->getMembers(), true);
|
|
writeDefaultWitnessTable(proto, DeclTypeAbbrCodes);
|
|
break;
|
|
}
|
|
|
|
case DeclKind::Var: {
|
|
auto var = cast<VarDecl>(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<ParamDecl>(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));
|
|
break;
|
|
}
|
|
|
|
case DeclKind::Func: {
|
|
auto fn = cast<FuncDecl>(D);
|
|
verifyAttrSerializable(fn);
|
|
|
|
auto contextID = addDeclContextRef(fn->getDeclContext());
|
|
|
|
unsigned abbrCode = DeclTypeAbbrCodes[FuncLayout::Code];
|
|
SmallVector<IdentifierID, 4> 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<EnumElementDecl>(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<IntegerLiteralExpr>(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<SubscriptDecl>(D);
|
|
verifyAttrSerializable(subscript);
|
|
|
|
auto contextID = addDeclContextRef(subscript->getDeclContext());
|
|
|
|
SmallVector<IdentifierID, 4> 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,
|
|
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);
|
|
|
|
writeParameterList(subscript->getIndices());
|
|
break;
|
|
}
|
|
|
|
|
|
case DeclKind::Constructor: {
|
|
auto ctor = cast<ConstructorDecl>(D);
|
|
verifyAttrSerializable(ctor);
|
|
|
|
auto contextID = addDeclContextRef(ctor->getDeclContext());
|
|
|
|
SmallVector<IdentifierID, 4> 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<DestructorDecl>(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<ValueDecl*, 4> CurModuleResults;
|
|
Ctx.TheBuiltinModule->lookupValue(ModuleDecl::AccessPathTy(),
|
|
Ctx.getIdentifier(TypeName),
|
|
NLKind::QualifiedLookup,
|
|
CurModuleResults);
|
|
assert(CurModuleResults.size() == 1);
|
|
return cast<TypeAliasDecl>(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<BuiltinType>());
|
|
|
|
unsigned abbrCode = DeclTypeAbbrCodes[NameAliasTypeLayout::Code];
|
|
NameAliasTypeLayout::emitRecord(Out, ScratchRecord, abbrCode,
|
|
addDeclRef(typeAlias));
|
|
break;
|
|
}
|
|
case TypeKind::NameAlias: {
|
|
auto nameAlias = cast<NameAliasType>(ty.getPointer());
|
|
const TypeAliasDecl *typeAlias = nameAlias->getDecl();
|
|
|
|
unsigned abbrCode = DeclTypeAbbrCodes[NameAliasTypeLayout::Code];
|
|
NameAliasTypeLayout::emitRecord(Out, ScratchRecord, abbrCode,
|
|
addDeclRef(typeAlias));
|
|
break;
|
|
}
|
|
|
|
case TypeKind::Paren: {
|
|
auto parenTy = cast<ParenType>(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<TupleType>(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<NominalType>(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<ExistentialMetatypeType>(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<uint8_t>(repr));
|
|
break;
|
|
}
|
|
|
|
case TypeKind::Metatype: {
|
|
auto metatypeTy = cast<MetatypeType>(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<uint8_t>(repr));
|
|
break;
|
|
}
|
|
|
|
case TypeKind::Module:
|
|
llvm_unreachable("modules are currently not first-class values");
|
|
|
|
case TypeKind::DynamicSelf: {
|
|
auto dynamicSelfTy = cast<DynamicSelfType>(ty.getPointer());
|
|
unsigned abbrCode = DeclTypeAbbrCodes[DynamicSelfTypeLayout::Code];
|
|
DynamicSelfTypeLayout::emitRecord(Out, ScratchRecord, abbrCode,
|
|
addTypeRef(dynamicSelfTy->getSelfType()));
|
|
break;
|
|
}
|
|
|
|
case TypeKind::Archetype: {
|
|
auto archetypeTy = cast<ArchetypeType>(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;
|
|
}
|
|
|
|
SmallVector<DeclID, 4> conformances;
|
|
for (auto proto : archetypeTy->getConformsTo())
|
|
conformances.push_back(addDeclRef(proto));
|
|
|
|
TypeID parentOrGenericEnv;
|
|
DeclID assocTypeOrNameID;
|
|
if (archetypeTy->getParent()) {
|
|
parentOrGenericEnv = addTypeRef(archetypeTy->getParent());
|
|
assocTypeOrNameID = addDeclRef(archetypeTy->getAssocType());
|
|
} else {
|
|
parentOrGenericEnv =
|
|
addGenericEnvironmentRef(archetypeTy->getGenericEnvironment());
|
|
assocTypeOrNameID = addIdentifierRef(archetypeTy->getName());
|
|
}
|
|
|
|
unsigned abbrCode = DeclTypeAbbrCodes[ArchetypeTypeLayout::Code];
|
|
ArchetypeTypeLayout::emitRecord(Out, ScratchRecord, abbrCode,
|
|
archetypeTy->isPrimary(),
|
|
parentOrGenericEnv,
|
|
assocTypeOrNameID,
|
|
addTypeRef(archetypeTy->getSuperclass()),
|
|
conformances);
|
|
|
|
SmallVector<IdentifierID, 4> nestedTypeNames;
|
|
SmallVector<TypeID, 4> nestedTypes;
|
|
for (auto next : archetypeTy->getAllNestedTypes()) {
|
|
nestedTypeNames.push_back(addIdentifierRef(next.first));
|
|
nestedTypes.push_back(addTypeRef(next.second));
|
|
}
|
|
|
|
abbrCode = DeclTypeAbbrCodes[ArchetypeNestedTypeNamesLayout::Code];
|
|
ArchetypeNestedTypeNamesLayout::emitRecord(Out, ScratchRecord, abbrCode,
|
|
nestedTypeNames);
|
|
|
|
abbrCode = DeclTypeAbbrCodes[ArchetypeNestedTypesLayout::Code];
|
|
ArchetypeNestedTypesLayout::emitRecord(Out, ScratchRecord, abbrCode,
|
|
nestedTypes);
|
|
|
|
break;
|
|
}
|
|
|
|
case TypeKind::GenericTypeParam: {
|
|
auto genericParam = cast<GenericTypeParamType>(ty.getPointer());
|
|
unsigned abbrCode = DeclTypeAbbrCodes[GenericTypeParamTypeLayout::Code];
|
|
DeclID declIDOrDepth;
|
|
unsigned indexPlusOne;
|
|
if (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<DependentMemberType>(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<FunctionType>(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<GenericFunctionType>(ty.getPointer());
|
|
unsigned abbrCode = DeclTypeAbbrCodes[GenericFunctionTypeLayout::Code];
|
|
SmallVector<TypeID, 4> 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<SILBlockStorageType>(ty.getPointer());
|
|
|
|
unsigned abbrCode = DeclTypeAbbrCodes[SILBlockStorageTypeLayout::Code];
|
|
SILBlockStorageTypeLayout::emitRecord(Out, ScratchRecord, abbrCode,
|
|
addTypeRef(storageTy->getCaptureType()));
|
|
break;
|
|
}
|
|
|
|
case TypeKind::SILBox: {
|
|
auto boxTy = cast<SILBoxType>(ty.getPointer());
|
|
|
|
unsigned abbrCode = DeclTypeAbbrCodes[SILBoxTypeLayout::Code];
|
|
SILLayoutID layoutRef = addSILLayoutRef(boxTy->getLayout());
|
|
|
|
#ifndef NDEBUG
|
|
if (auto sig = boxTy->getLayout()->getGenericSignature()) {
|
|
assert(sig->getAllDependentTypes().size()
|
|
== 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<SILFunctionType>(ty.getPointer());
|
|
|
|
auto representation = fnTy->getRepresentation();
|
|
auto stableRepresentation =
|
|
getRawStableSILFunctionTypeRepresentation(representation);
|
|
|
|
SmallVector<TypeID, 8> 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<ArraySliceType>(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<DictionaryType>(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<OptionalType>(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<ImplicitlyUnwrappedOptionalType>(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<ProtocolCompositionType>(ty.getPointer());
|
|
|
|
SmallVector<TypeID, 4> protocols;
|
|
for (auto proto : composition->getProtocols())
|
|
protocols.push_back(addTypeRef(proto));
|
|
|
|
unsigned abbrCode = DeclTypeAbbrCodes[ProtocolCompositionTypeLayout::Code];
|
|
ProtocolCompositionTypeLayout::emitRecord(Out, ScratchRecord, abbrCode,
|
|
protocols);
|
|
break;
|
|
}
|
|
|
|
case TypeKind::LValue: {
|
|
auto lValueTy = cast<LValueType>(ty.getPointer());
|
|
|
|
unsigned abbrCode = DeclTypeAbbrCodes[LValueTypeLayout::Code];
|
|
LValueTypeLayout::emitRecord(Out, ScratchRecord, abbrCode,
|
|
addTypeRef(lValueTy->getObjectType()));
|
|
break;
|
|
}
|
|
case TypeKind::InOut: {
|
|
auto iotTy = cast<InOutType>(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<ReferenceStorageType>(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<UnboundGenericType>(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<BoundGenericType>(ty.getPointer());
|
|
SmallVector<TypeID, 8> 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<NameAliasTypeLayout>();
|
|
registerDeclTypeAbbr<GenericTypeParamDeclLayout>();
|
|
registerDeclTypeAbbr<AssociatedTypeDeclLayout>();
|
|
registerDeclTypeAbbr<NominalTypeLayout>();
|
|
registerDeclTypeAbbr<ParenTypeLayout>();
|
|
registerDeclTypeAbbr<TupleTypeLayout>();
|
|
registerDeclTypeAbbr<TupleTypeEltLayout>();
|
|
registerDeclTypeAbbr<FunctionTypeLayout>();
|
|
registerDeclTypeAbbr<MetatypeTypeLayout>();
|
|
registerDeclTypeAbbr<ExistentialMetatypeTypeLayout>();
|
|
registerDeclTypeAbbr<LValueTypeLayout>();
|
|
registerDeclTypeAbbr<InOutTypeLayout>();
|
|
registerDeclTypeAbbr<ArchetypeTypeLayout>();
|
|
registerDeclTypeAbbr<ArchetypeNestedTypeNamesLayout>();
|
|
registerDeclTypeAbbr<ArchetypeNestedTypesLayout>();
|
|
registerDeclTypeAbbr<ProtocolCompositionTypeLayout>();
|
|
registerDeclTypeAbbr<BoundGenericTypeLayout>();
|
|
registerDeclTypeAbbr<BoundGenericSubstitutionLayout>();
|
|
registerDeclTypeAbbr<GenericFunctionTypeLayout>();
|
|
registerDeclTypeAbbr<SILBlockStorageTypeLayout>();
|
|
registerDeclTypeAbbr<SILBoxTypeLayout>();
|
|
registerDeclTypeAbbr<SILFunctionTypeLayout>();
|
|
registerDeclTypeAbbr<ArraySliceTypeLayout>();
|
|
registerDeclTypeAbbr<DictionaryTypeLayout>();
|
|
registerDeclTypeAbbr<ReferenceStorageTypeLayout>();
|
|
registerDeclTypeAbbr<UnboundGenericTypeLayout>();
|
|
registerDeclTypeAbbr<OptionalTypeLayout>();
|
|
registerDeclTypeAbbr<ImplicitlyUnwrappedOptionalTypeLayout>();
|
|
registerDeclTypeAbbr<DynamicSelfTypeLayout>();
|
|
registerDeclTypeAbbr<OpenedExistentialTypeLayout>();
|
|
|
|
registerDeclTypeAbbr<TypeAliasLayout>();
|
|
registerDeclTypeAbbr<GenericTypeParamTypeLayout>();
|
|
registerDeclTypeAbbr<DependentMemberTypeLayout>();
|
|
registerDeclTypeAbbr<StructLayout>();
|
|
registerDeclTypeAbbr<ConstructorLayout>();
|
|
registerDeclTypeAbbr<VarLayout>();
|
|
registerDeclTypeAbbr<ParamLayout>();
|
|
registerDeclTypeAbbr<FuncLayout>();
|
|
registerDeclTypeAbbr<PatternBindingLayout>();
|
|
registerDeclTypeAbbr<ProtocolLayout>();
|
|
registerDeclTypeAbbr<DefaultWitnessTableLayout>();
|
|
registerDeclTypeAbbr<PrefixOperatorLayout>();
|
|
registerDeclTypeAbbr<PostfixOperatorLayout>();
|
|
registerDeclTypeAbbr<InfixOperatorLayout>();
|
|
registerDeclTypeAbbr<PrecedenceGroupLayout>();
|
|
registerDeclTypeAbbr<ClassLayout>();
|
|
registerDeclTypeAbbr<EnumLayout>();
|
|
registerDeclTypeAbbr<EnumElementLayout>();
|
|
registerDeclTypeAbbr<SubscriptLayout>();
|
|
registerDeclTypeAbbr<ExtensionLayout>();
|
|
registerDeclTypeAbbr<DestructorLayout>();
|
|
|
|
registerDeclTypeAbbr<ParameterListLayout>();
|
|
registerDeclTypeAbbr<ParameterListEltLayout>();
|
|
|
|
registerDeclTypeAbbr<ParenPatternLayout>();
|
|
registerDeclTypeAbbr<TuplePatternLayout>();
|
|
registerDeclTypeAbbr<TuplePatternEltLayout>();
|
|
registerDeclTypeAbbr<NamedPatternLayout>();
|
|
registerDeclTypeAbbr<VarPatternLayout>();
|
|
registerDeclTypeAbbr<AnyPatternLayout>();
|
|
registerDeclTypeAbbr<TypedPatternLayout>();
|
|
registerDeclTypeAbbr<GenericParamListLayout>();
|
|
registerDeclTypeAbbr<GenericParamLayout>();
|
|
registerDeclTypeAbbr<GenericRequirementLayout>();
|
|
registerDeclTypeAbbr<GenericEnvironmentLayout>();
|
|
registerDeclTypeAbbr<SILGenericEnvironmentLayout>();
|
|
|
|
registerDeclTypeAbbr<ForeignErrorConventionLayout>();
|
|
registerDeclTypeAbbr<DeclContextLayout>();
|
|
registerDeclTypeAbbr<AbstractClosureExprLayout>();
|
|
registerDeclTypeAbbr<PatternBindingInitializerLayout>();
|
|
registerDeclTypeAbbr<DefaultArgumentInitializerLayout>();
|
|
registerDeclTypeAbbr<TopLevelCodeDeclContextLayout>();
|
|
|
|
registerDeclTypeAbbr<XRefTypePathPieceLayout>();
|
|
registerDeclTypeAbbr<XRefValuePathPieceLayout>();
|
|
registerDeclTypeAbbr<XRefExtensionPathPieceLayout>();
|
|
registerDeclTypeAbbr<XRefOperatorOrAccessorPathPieceLayout>();
|
|
registerDeclTypeAbbr<XRefGenericParamPathPieceLayout>();
|
|
registerDeclTypeAbbr<XRefInitializerPathPieceLayout>();
|
|
|
|
registerDeclTypeAbbr<AbstractProtocolConformanceLayout>();
|
|
registerDeclTypeAbbr<NormalProtocolConformanceLayout>();
|
|
registerDeclTypeAbbr<SpecializedProtocolConformanceLayout>();
|
|
registerDeclTypeAbbr<InheritedProtocolConformanceLayout>();
|
|
registerDeclTypeAbbr<NormalProtocolConformanceIdLayout>();
|
|
registerDeclTypeAbbr<ProtocolConformanceXrefLayout>();
|
|
|
|
registerDeclTypeAbbr<SILLayoutLayout>();
|
|
|
|
registerDeclTypeAbbr<LocalDiscriminatorLayout>();
|
|
registerDeclTypeAbbr<PrivateDiscriminatorLayout>();
|
|
registerDeclTypeAbbr<MembersLayout>();
|
|
registerDeclTypeAbbr<XRefLayout>();
|
|
|
|
#define DECL_ATTR(X, NAME, ...) \
|
|
registerDeclTypeAbbr<NAME##DeclAttrLayout>();
|
|
#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<BitOffset> &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<uint64_t, 8> scratch;
|
|
llvm::SmallString<4096> hashTableBlob;
|
|
uint32_t tableOffset;
|
|
{
|
|
llvm::OnDiskChainedHashTableGenerator<DeclTableInfo> 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<little>(blobStream).write<uint32_t>(0);
|
|
tableOffset = generator.Emit(blobStream);
|
|
}
|
|
|
|
DeclList.emit(scratch, kind, tableOffset, hashTableBlob);
|
|
}
|
|
|
|
static void writeLocalDeclTable(const index_block::DeclListLayout &DeclList,
|
|
index_block::RecordKind kind,
|
|
LocalTypeHashTableGenerator &generator) {
|
|
SmallVector<uint64_t, 8> 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<little>(blobStream).write<uint32_t>(0);
|
|
tableOffset = generator.Emit(blobStream);
|
|
}
|
|
|
|
DeclList.emit(scratch, kind, tableOffset, hashTableBlob);
|
|
}
|
|
|
|
static void
|
|
writeNestedTypeDeclsTable(const index_block::NestedTypeDeclsLayout &declList,
|
|
const Serializer::NestedTypeDeclsTable &table) {
|
|
SmallVector<uint64_t, 8> scratch;
|
|
llvm::SmallString<4096> hashTableBlob;
|
|
uint32_t tableOffset;
|
|
{
|
|
llvm::OnDiskChainedHashTableGenerator<NestedTypeDeclsTableInfo> 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<little>(blobStream).write<uint32_t>(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<unsigned, unsigned>
|
|
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<little> writer(out);
|
|
writer.write<uint32_t>(keyLength);
|
|
writer.write<uint32_t>(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<little> writer(out);
|
|
writer.write<uint32_t>(data.Brief.size());
|
|
out << data.Brief;
|
|
writer.write<uint32_t>(data.Raw.Comments.size());
|
|
for (auto C : data.Raw.Comments) {
|
|
writer.write<uint32_t>(C.StartColumn);
|
|
writer.write<uint32_t>(C.RawText.size());
|
|
out << C.RawText;
|
|
}
|
|
writer.write<uint32_t>(data.Group);
|
|
writer.write<uint32_t>(data.Order);
|
|
}
|
|
};
|
|
|
|
} // end unnamed namespace
|
|
|
|
typedef llvm::StringMap<std::string> FileNameToGroupNameMap;
|
|
typedef std::unique_ptr<FileNameToGroupNameMap> pFileNameToGroupNameMap;
|
|
|
|
class YamlGroupInputParser {
|
|
StringRef RecordPath;
|
|
std::string Separator = "/";
|
|
static llvm::StringMap<pFileNameToGroupNameMap> AllMaps;
|
|
|
|
bool parseRoot(FileNameToGroupNameMap &Map, llvm::yaml::Node *Root,
|
|
const llvm::Twine &ParentName) {
|
|
llvm::yaml::MappingNode *MapNode = dyn_cast<llvm::yaml::MappingNode>(Root);
|
|
if (!MapNode) {
|
|
return true;
|
|
}
|
|
for (auto Pair : *MapNode) {
|
|
auto *Key = dyn_cast_or_null<llvm::yaml::ScalarNode>(Pair.getKey());
|
|
auto *Value = dyn_cast_or_null<llvm::yaml::SequenceNode>(Pair.getValue());
|
|
|
|
if (!Key || !Value) {
|
|
return true;
|
|
}
|
|
llvm::SmallString<16> GroupNameStorage;
|
|
StringRef GroupName = Key->getValue(GroupNameStorage);
|
|
std::unique_ptr<llvm::Twine> 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<llvm::yaml::ScalarNode>(&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<llvm::yaml::MappingNode>(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<pFileNameToGroupNameMap> 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<StringRef, unsigned> Map;
|
|
std::vector<StringRef> ViewBuffer;
|
|
std::unique_ptr<GroupNameCollector> 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<StringRef> 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<StringRef> Names) {
|
|
llvm::SmallString<32> Blob;
|
|
llvm::raw_svector_ostream BlobStream(Blob);
|
|
endian::Writer<little> Writer(BlobStream);
|
|
Writer.write<uint32_t>(Names.size());
|
|
for (auto N : Names) {
|
|
Writer.write<uint32_t>(N.size());
|
|
BlobStream << N;
|
|
}
|
|
SmallVector<uint64_t, 8> 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<DeclCommentTableInfo> generator;
|
|
DeclGroupNameContext &GroupContext;
|
|
unsigned SourceOrder;
|
|
|
|
DeclCommentTableWriter(DeclGroupNameContext &GroupContext) :
|
|
GroupContext(GroupContext) {}
|
|
|
|
void resetSourceOrder() {
|
|
SourceOrder = 0;
|
|
}
|
|
|
|
StringRef copyString(StringRef String) {
|
|
char *Mem = static_cast<char *>(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<ExtensionDecl>(D)) {
|
|
writeDocForExtensionDecl(ED);
|
|
return true;
|
|
}
|
|
|
|
auto *VD = dyn_cast<ValueDecl>(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<const FileUnit *> files;
|
|
SmallVector<const FileUnit *, 1> Scratch;
|
|
if (SF) {
|
|
Scratch.push_back(SF);
|
|
files = llvm::makeArrayRef(Scratch);
|
|
} else {
|
|
files = M->getFiles();
|
|
}
|
|
for (auto nextFile : files) {
|
|
Writer.resetSourceOrder();
|
|
const_cast<FileUnit *>(nextFile)->walk(Writer);
|
|
}
|
|
SmallVector<uint64_t, 8> 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<little>(blobStream).write<uint32_t>(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<unsigned, unsigned> 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<uint16_t>::max() &&
|
|
"selector too long");
|
|
size_t entrySize = sizeof(uint32_t) + 1 + sizeof(uint32_t);
|
|
uint16_t dataLength = entrySize * data.size();
|
|
assert(dataLength / entrySize == data.size() && "too many methods");
|
|
|
|
endian::Writer<little> writer(out);
|
|
writer.write<uint16_t>(keyLength);
|
|
writer.write<uint16_t>(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<little> writer(out);
|
|
for (auto entry : data) {
|
|
writer.write<uint32_t>(std::get<0>(entry));
|
|
writer.write<uint8_t>(std::get<1>(entry));
|
|
writer.write<uint32_t>(std::get<2>(entry));
|
|
}
|
|
}
|
|
};
|
|
} // 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<ObjCSelector> 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<ObjCMethodTableInfo> 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<little>(blobStream).write<uint32_t>(0);
|
|
tableOffset = generator.Emit(blobStream);
|
|
}
|
|
|
|
SmallVector<uint64_t, 8> scratch;
|
|
out.emit(scratch, tableOffset, hashTableBlob);
|
|
}
|
|
|
|
/// Recursively walks the members and derived global decls of any nominal types
|
|
/// to build up global tables.
|
|
template<typename Range>
|
|
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<ValueDecl>(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<TypeDecl>(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<IterableDeclContext>(member)) {
|
|
collectInterestingNestedDeclarations(S, iterable->getMembers(),
|
|
operatorMethodDecls,
|
|
objcMethods, nestedTypeDecls,
|
|
isLocal);
|
|
}
|
|
|
|
// Record Objective-C methods.
|
|
if (!isLocal) {
|
|
if (auto func = dyn_cast<AbstractFunctionDecl>(member)) {
|
|
if (func->isObjC()) {
|
|
TypeID owningTypeID
|
|
= S.addTypeRef(func->getDeclContext()->getDeclaredInterfaceType());
|
|
objcMethods[func->getObjCSelector()].push_back(
|
|
std::make_tuple(owningTypeID,
|
|
func->isObjCInstanceMethod(),
|
|
S.addDeclRef(func)));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Serializer::writeAST(ModuleOrSourceFile DC,
|
|
bool enableNestedTypeLookupTable) {
|
|
DeclTable topLevelDecls, extensionDecls, operatorDecls, operatorMethodDecls;
|
|
DeclTable precedenceGroupDecls;
|
|
ObjCMethodTable objcMethods;
|
|
NestedTypeDeclsTable nestedTypeDecls;
|
|
LocalTypeHashTableGenerator localTypeGenerator;
|
|
bool hasLocalTypes = false;
|
|
|
|
Optional<DeclID> entryPointClassID;
|
|
|
|
ArrayRef<const FileUnit *> files;
|
|
SmallVector<const FileUnit *, 1> 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<Decl *, 32> fileDecls;
|
|
nextFile->getTopLevelDecls(fileDecls);
|
|
|
|
for (auto D : fileDecls) {
|
|
if (isa<ImportDecl>(D))
|
|
continue;
|
|
|
|
if (auto VD = dyn_cast<ValueDecl>(D)) {
|
|
if (!VD->hasName())
|
|
continue;
|
|
topLevelDecls[VD->getName()]
|
|
.push_back({ getKindForTable(D), addDeclRef(D) });
|
|
} else if (auto ED = dyn_cast<ExtensionDecl>(D)) {
|
|
Type extendedTy = ED->getExtendedType();
|
|
const NominalTypeDecl *extendedNominal = extendedTy->getAnyNominal();
|
|
extensionDecls[extendedNominal->getName()]
|
|
.push_back({ getKindForTable(extendedNominal), addDeclRef(D) });
|
|
} else if (auto OD = dyn_cast<OperatorDecl>(D)) {
|
|
operatorDecls[OD->getName()]
|
|
.push_back({ getStableFixity(OD->getKind()), addDeclRef(D) });
|
|
} else if (auto PGD = dyn_cast<PrecedenceGroupDecl>(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<VarDecl>(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<IterableDeclContext>(D)) {
|
|
collectInterestingNestedDeclarations(*this, IDC->getMembers(),
|
|
operatorMethodDecls, objcMethods,
|
|
nestedTypeDecls);
|
|
}
|
|
}
|
|
|
|
SmallVector<TypeDecl *, 16> localTypeDecls;
|
|
nextFile->getLocalTypeDecls(localTypeDecls);
|
|
|
|
for (auto TD : localTypeDecls) {
|
|
hasLocalTypes = true;
|
|
std::string MangledName = NewMangling::mangleTypeAsUSR(
|
|
TD->getDeclaredInterfaceType());
|
|
assert(!MangledName.empty() && "Mangled type came back empty!");
|
|
localTypeGenerator.insert(MangledName, {
|
|
addDeclRef(TD), TD->getLocalDiscriminator()
|
|
});
|
|
|
|
if (auto IDC = dyn_cast<IterableDeclContext>(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::EXTENSIONS, extensionDecls);
|
|
writeDeclTable(DeclList, index_block::CLASS_MEMBERS, ClassMembersByName);
|
|
writeDeclTable(DeclList, index_block::OPERATOR_METHODS, operatorMethodDecls);
|
|
if (hasLocalTypes)
|
|
writeLocalDeclTable(DeclList, index_block::LOCAL_TYPE_DECLS,
|
|
localTypeGenerator);
|
|
|
|
index_block::ObjCMethodTableLayout ObjCMethodTable(Out);
|
|
writeObjCMethodTable(ObjCMethodTable, objcMethods);
|
|
|
|
if (DC.is<SourceFile *>() && 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 <size_t N>
|
|
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<SourceFile *>();
|
|
}
|
|
|
|
|
|
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<void(raw_ostream &)> action){
|
|
namespace path = llvm::sys::path;
|
|
clang::CompilerInstance Clang;
|
|
|
|
std::string tmpFilePath;
|
|
{
|
|
std::error_code EC;
|
|
std::unique_ptr<llvm::raw_pwrite_stream> 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));
|
|
});
|
|
}
|
|
}
|