mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[serialization] Record nominal types in the module table ASAP.
Deserializing a nominal decl often ends up referring to the nominal's type, so if we're /already/ serializing the type, we should finish that as soon as we have a decl. Accomplish this by adding a callback that is called right after a nominal decl is recorded in the module's decl table, so that the type can be immediately recorded as well. Swift SVN r6227
This commit is contained in:
@@ -16,12 +16,32 @@
|
|||||||
#include "swift/Basic/STLExtras.h"
|
#include "swift/Basic/STLExtras.h"
|
||||||
#include "swift/Serialization/BCReadingExtras.h"
|
#include "swift/Serialization/BCReadingExtras.h"
|
||||||
#include "llvm/Support/MemoryBuffer.h"
|
#include "llvm/Support/MemoryBuffer.h"
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
using namespace swift;
|
using namespace swift;
|
||||||
using namespace swift::serialization;
|
using namespace swift::serialization;
|
||||||
static constexpr const auto AF_DontPopBlockAtEnd =
|
static constexpr const auto AF_DontPopBlockAtEnd =
|
||||||
llvm::BitstreamCursor::AF_DontPopBlockAtEnd;
|
llvm::BitstreamCursor::AF_DontPopBlockAtEnd;
|
||||||
|
|
||||||
|
/// Declares a member \c type that is a std::function compatible with the given
|
||||||
|
/// callable type.
|
||||||
|
///
|
||||||
|
/// \tparam T A callable type, such as a lambda.
|
||||||
|
template <typename T>
|
||||||
|
struct as_function : public as_function<decltype(&T::operator())> {};
|
||||||
|
|
||||||
|
template <typename L, typename R, typename... Args>
|
||||||
|
struct as_function<R(L::*)(Args...) const> {
|
||||||
|
using type = std::function<R(Args...)>;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Returns a std::function that can call a void-returning, single-argument
|
||||||
|
/// lambda without copying it.
|
||||||
|
template <typename L>
|
||||||
|
static typename as_function<L>::type makeStackLambda(const L &theLambda) {
|
||||||
|
return std::cref(theLambda);
|
||||||
|
}
|
||||||
|
|
||||||
static ModuleStatus
|
static ModuleStatus
|
||||||
validateControlBlock(llvm::BitstreamCursor &cursor,
|
validateControlBlock(llvm::BitstreamCursor &cursor,
|
||||||
llvm::SmallVectorImpl<uint64_t> &scratch) {
|
llvm::SmallVectorImpl<uint64_t> &scratch) {
|
||||||
@@ -178,16 +198,15 @@ Optional<ProtocolConformance *> ModuleFile::maybeReadConformance() {
|
|||||||
return Nothing;
|
return Nothing;
|
||||||
|
|
||||||
unsigned kind = DeclTypeCursor.readRecord(next.ID, scratch);
|
unsigned kind = DeclTypeCursor.readRecord(next.ID, scratch);
|
||||||
if (kind == NO_CONFORMANCE) {
|
if (kind != PROTOCOL_CONFORMANCE && kind != NO_CONFORMANCE)
|
||||||
assert(scratch.empty());
|
|
||||||
lastRecordOffset.reset();
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (kind != PROTOCOL_CONFORMANCE)
|
|
||||||
return Nothing;
|
return Nothing;
|
||||||
|
|
||||||
lastRecordOffset.reset();
|
lastRecordOffset.reset();
|
||||||
|
if (kind == NO_CONFORMANCE) {
|
||||||
|
assert(scratch.empty());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
unsigned valueCount, typeCount, inheritedCount, defaultedCount;
|
unsigned valueCount, typeCount, inheritedCount, defaultedCount;
|
||||||
ArrayRef<uint64_t> rawIDs;
|
ArrayRef<uint64_t> rawIDs;
|
||||||
|
|
||||||
@@ -222,13 +241,13 @@ Optional<ProtocolConformance *> ModuleFile::maybeReadConformance() {
|
|||||||
|
|
||||||
auto inherited = maybeReadConformance();
|
auto inherited = maybeReadConformance();
|
||||||
assert(inherited.hasValue());
|
assert(inherited.hasValue());
|
||||||
lastRecordOffset.reset();
|
|
||||||
|
|
||||||
conformance->InheritedMapping.insert(std::make_pair(proto, *inherited));
|
conformance->InheritedMapping.insert(std::make_pair(proto, *inherited));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lastRecordOffset.reset();
|
||||||
|
|
||||||
while (defaultedCount--) {
|
while (defaultedCount--) {
|
||||||
BCOffsetRAII restoreOffset(DeclTypeCursor);
|
|
||||||
auto decl = cast<ValueDecl>(getDecl(*rawIDIter++));
|
auto decl = cast<ValueDecl>(getDecl(*rawIDIter++));
|
||||||
conformance->DefaultedDefinitions.insert(decl);
|
conformance->DefaultedDefinitions.insert(decl);
|
||||||
}
|
}
|
||||||
@@ -382,8 +401,7 @@ Optional<MutableArrayRef<Decl *>> ModuleFile::readMembers() {
|
|||||||
SmallVector<uint64_t, 16> memberIDBuffer;
|
SmallVector<uint64_t, 16> memberIDBuffer;
|
||||||
|
|
||||||
unsigned kind = DeclTypeCursor.readRecord(entry.ID, memberIDBuffer);
|
unsigned kind = DeclTypeCursor.readRecord(entry.ID, memberIDBuffer);
|
||||||
if (kind != DECL_CONTEXT)
|
assert(kind == DECL_CONTEXT);
|
||||||
return Nothing;
|
|
||||||
|
|
||||||
ArrayRef<uint64_t> rawMemberIDs;
|
ArrayRef<uint64_t> rawMemberIDs;
|
||||||
decls_block::DeclContextLayout::readRecord(memberIDBuffer, rawMemberIDs);
|
decls_block::DeclContextLayout::readRecord(memberIDBuffer, rawMemberIDs);
|
||||||
@@ -463,15 +481,20 @@ static Optional<swift::Associativity> getActualAssociativity(uint8_t assoc) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Decl *ModuleFile::getDecl(DeclID DID, Optional<DeclContext *> ForcedContext) {
|
Decl *ModuleFile::getDecl(DeclID DID, Optional<DeclContext *> ForcedContext,
|
||||||
|
Optional<std::function<void(Decl*)>> DidRecord) {
|
||||||
if (DID == 0)
|
if (DID == 0)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
assert(DID <= Decls.size() && "invalid decl ID");
|
assert(DID <= Decls.size() && "invalid decl ID");
|
||||||
auto &declOrOffset = Decls[DID-1];
|
auto &declOrOffset = Decls[DID-1];
|
||||||
|
|
||||||
if (declOrOffset.is<Decl *>())
|
if (declOrOffset.is<Decl *>()) {
|
||||||
return declOrOffset.get<Decl *>();
|
auto result = declOrOffset.get<Decl *>();
|
||||||
|
if (DidRecord)
|
||||||
|
(*DidRecord)(result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
DeclTypeCursor.JumpToBit(declOrOffset.get<BitOffset>());
|
DeclTypeCursor.JumpToBit(declOrOffset.get<BitOffset>());
|
||||||
auto entry = DeclTypeCursor.advance();
|
auto entry = DeclTypeCursor.advance();
|
||||||
@@ -570,6 +593,8 @@ Decl *ModuleFile::getDecl(DeclID DID, Optional<DeclContext *> ForcedContext) {
|
|||||||
SourceLoc(), inherited,
|
SourceLoc(), inherited,
|
||||||
genericParams, DC);
|
genericParams, DC);
|
||||||
declOrOffset = theStruct;
|
declOrOffset = theStruct;
|
||||||
|
if (DidRecord)
|
||||||
|
(*DidRecord)(theStruct);
|
||||||
|
|
||||||
if (isImplicit)
|
if (isImplicit)
|
||||||
theStruct->setImplicit();
|
theStruct->setImplicit();
|
||||||
@@ -800,6 +825,8 @@ Decl *ModuleFile::getDecl(DeclID DID, Optional<DeclContext *> ForcedContext) {
|
|||||||
SourceLoc(), getIdentifier(nameID),
|
SourceLoc(), getIdentifier(nameID),
|
||||||
inherited);
|
inherited);
|
||||||
declOrOffset = proto;
|
declOrOffset = proto;
|
||||||
|
if (DidRecord)
|
||||||
|
(*DidRecord)(proto);
|
||||||
|
|
||||||
if (isImplicit)
|
if (isImplicit)
|
||||||
proto->setImplicit();
|
proto->setImplicit();
|
||||||
@@ -893,6 +920,8 @@ Decl *ModuleFile::getDecl(DeclID DID, Optional<DeclContext *> ForcedContext) {
|
|||||||
SourceLoc(), inherited,
|
SourceLoc(), inherited,
|
||||||
genericParams, DC);
|
genericParams, DC);
|
||||||
declOrOffset = theClass;
|
declOrOffset = theClass;
|
||||||
|
if (DidRecord)
|
||||||
|
(*DidRecord)(theClass);
|
||||||
|
|
||||||
if (isImplicit)
|
if (isImplicit)
|
||||||
theClass->setImplicit();
|
theClass->setImplicit();
|
||||||
@@ -940,6 +969,8 @@ Decl *ModuleFile::getDecl(DeclID DID, Optional<DeclContext *> ForcedContext) {
|
|||||||
SourceLoc(), inherited,
|
SourceLoc(), inherited,
|
||||||
genericParams, DC);
|
genericParams, DC);
|
||||||
declOrOffset = oneOf;
|
declOrOffset = oneOf;
|
||||||
|
if (DidRecord)
|
||||||
|
(*DidRecord)(oneOf);
|
||||||
|
|
||||||
if (isImplicit)
|
if (isImplicit)
|
||||||
oneOf->setImplicit();
|
oneOf->setImplicit();
|
||||||
@@ -1290,8 +1321,17 @@ Type ModuleFile::getType(TypeID TID) {
|
|||||||
DeclID declID;
|
DeclID declID;
|
||||||
TypeID parentID;
|
TypeID parentID;
|
||||||
decls_block::NominalTypeLayout::readRecord(scratch, declID, parentID);
|
decls_block::NominalTypeLayout::readRecord(scratch, declID, parentID);
|
||||||
typeOrOffset = NominalType::get(cast<NominalTypeDecl>(getDecl(declID)),
|
|
||||||
getType(parentID), ctx);
|
Type parentTy = getType(parentID);
|
||||||
|
|
||||||
|
// Record the type as soon as possible. Members of a nominal type often
|
||||||
|
// try to refer back to the type.
|
||||||
|
getDecl(declID, Nothing, makeStackLambda([&](Decl *D) {
|
||||||
|
auto nominal = cast<NominalTypeDecl>(D);
|
||||||
|
typeOrOffset = NominalType::get(nominal, parentTy, ctx);
|
||||||
|
}));
|
||||||
|
|
||||||
|
assert(typeOrOffset.is<Type>());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -188,8 +188,17 @@ private:
|
|||||||
DeclContext *getDeclContext(serialization::DeclID DID);
|
DeclContext *getDeclContext(serialization::DeclID DID);
|
||||||
|
|
||||||
/// Returns the decl with the given ID, deserializing it if needed.
|
/// Returns the decl with the given ID, deserializing it if needed.
|
||||||
|
///
|
||||||
|
/// \param DID The ID for the decl within this module.
|
||||||
|
/// \param ForcedContext Optional override for the decl context of certain
|
||||||
|
/// kinds of decls, used to avoid re-entrant
|
||||||
|
/// deserialization.
|
||||||
|
/// \param DidRecord Optional callback, called when certain kinds of decls
|
||||||
|
/// have been recorded in the decl table but not necessarily
|
||||||
|
/// completed.
|
||||||
Decl *getDecl(serialization::DeclID DID,
|
Decl *getDecl(serialization::DeclID DID,
|
||||||
Optional<DeclContext *> ForcedContext = {});
|
Optional<DeclContext *> ForcedContext = {},
|
||||||
|
Optional<std::function<void(Decl*)>> DidRecord = {});
|
||||||
|
|
||||||
/// Returns the type with the given ID, deserializing it if needed.
|
/// Returns the type with the given ID, deserializing it if needed.
|
||||||
Type getType(serialization::TypeID TID);
|
Type getType(serialization::TypeID TID);
|
||||||
|
|||||||
Reference in New Issue
Block a user