[serialization] Deserialize typealiases and builtin types.

This includes the reading half of BCRecordLayout metaprogramming, and
then a fairly straightforward deserialize-and-cache implementation in
ModuleFile. Once again, this is based on Clang's module implementation:
decls and types are referred to by an ID, which is used as an index into
an array, which contains offsets to the definitions of the decl/type in
the "decls-and-types" block in the serialized module.

In order to test the feature, the code is currently eagerly deserializing
all declarations. This will be partially fixed in the next commit.

Swift SVN r5324
This commit is contained in:
Jordan Rose
2013-05-25 01:34:56 +00:00
parent 9b712a2fe9
commit 76b19d53c4
6 changed files with 332 additions and 62 deletions

View File

@@ -12,6 +12,7 @@
#include "ModuleFile.h"
#include "ModuleFormat.h"
#include "swift/AST/AST.h"
#include "llvm/Support/MemoryBuffer.h"
using namespace swift;
@@ -61,8 +62,142 @@ validateControlBlock(llvm::BitstreamCursor &cursor,
return result;
}
const Decl *ModuleFile::getDecl(DeclID DID) {
if (DID == 0)
return nullptr;
assert(DID <= Decls.size() && "invalid decl ID");
auto &declOrOffset = Decls[DID-1];
if (declOrOffset.isPointer())
return declOrOffset.getPointer();
DeclTypeCursor.JumpToBit(declOrOffset.getInt());
auto entry = DeclTypeCursor.advance();
if (entry.Kind != llvm::BitstreamEntry::Record) {
// We don't know how to serialize decls represented by sub-blocks.
error();
return nullptr;
}
SmallVector<uint64_t, 64> scratch;
StringRef blobData;
unsigned recordID = DeclTypeCursor.readRecord(entry.ID, scratch, &blobData);
switch (recordID) {
case decls_block::TYPE_ALIAS_DECL: {
TypeID underlyingTypeID;
bool isGeneric;
bool isImplicit;
ArrayRef<uint64_t> inheritedIDs;
decls_block::TypeAliasLayout::readRecord(scratch, underlyingTypeID,
isGeneric, isImplicit,
inheritedIDs);
assert(inheritedIDs.empty() && "can't handle inherited IDs yet");
// Deserialize the name.
// FIXME: Move this to an identifier table instead of a trailing record.
entry = DeclTypeCursor.advance();
if (entry.Kind != llvm::BitstreamEntry::Record) {
error();
return nullptr;
}
SmallVector<uint64_t, 0> empty;
recordID = DeclTypeCursor.readRecord(entry.ID, empty, &blobData);
if (recordID != decls_block::NAME_HACK) {
error();
return nullptr;
}
assert(empty.empty() && "no data in NAME_HACK records");
assert(!blobData.empty() && "missing name in NAME_HACK record");
ASTContext &ctx = ModuleContext->Ctx;
TypeLoc underlyingType = TypeLoc::withoutLoc(getType(underlyingTypeID));
declOrOffset = new (ctx) TypeAliasDecl(SourceLoc(),
ctx.getIdentifier(blobData),
SourceLoc(),
underlyingType,
ModuleContext,
{});
break;
}
default:
// We don't know how to deserialize this kind of decl.
error();
return nullptr;
}
return declOrOffset.getPointer();
}
Type ModuleFile::getType(TypeID TID) {
if (TID == 0)
return Type();
assert(TID <= Types.size() && "invalid decl ID");
auto &typeOrOffset = Types[TID-1];
if (typeOrOffset.isPointer())
return typeOrOffset.getPointer();
DeclTypeCursor.JumpToBit(typeOrOffset.getInt());
auto entry = DeclTypeCursor.advance();
if (entry.Kind != llvm::BitstreamEntry::Record) {
// We don't know how to serialize types represented by sub-blocks.
error();
return nullptr;
}
SmallVector<uint64_t, 64> scratch;
StringRef blobData;
unsigned recordID = DeclTypeCursor.readRecord(entry.ID, scratch, &blobData);
switch (recordID) {
case decls_block::BUILTIN_TYPE: {
assert(!blobData.empty() && "missing name in BUILTIN_TYPE record");
SmallVector<ValueDecl *, 1> lookupResult;
ASTContext &ctx = ModuleContext->Ctx;
ctx.TheBuiltinModule->lookupValue({}, ctx.getIdentifier(blobData),
NLKind::QualifiedLookup, lookupResult);
if (lookupResult.empty()) {
// This builtin is not supported.
error();
return nullptr;
}
assert(lookupResult.size() == 1 && "multiple types for the same name");
typeOrOffset = cast<TypeDecl>(lookupResult.front())->getDeclaredType();
break;
}
case decls_block::NAME_ALIAS_TYPE: {
DeclID underlyingID;
decls_block::NameAliasTypeLayout::readRecord(scratch, underlyingID);
auto alias = dyn_cast_or_null<TypeAliasDecl>(getDecl(underlyingID));
if (!alias) {
error();
return nullptr;
}
typeOrOffset = alias->getDeclaredType();
break;
}
default:
// We don't know how to deserialize this kind of type.
error();
return nullptr;
}
return typeOrOffset.getPointer();
}
ModuleFile::ModuleFile(llvm::OwningPtr<llvm::MemoryBuffer> &&input)
: InputFile(std::move(input)),
: ModuleContext(nullptr),
InputFile(std::move(input)),
InputReader(reinterpret_cast<const uint8_t *>(InputFile->getBufferStart()),
reinterpret_cast<const uint8_t *>(InputFile->getBufferEnd())),
Status(ModuleStatus::Valid) {
@@ -129,6 +264,23 @@ ModuleFile::ModuleFile(llvm::OwningPtr<llvm::MemoryBuffer> &&input)
break;
}
case DECLS_AND_TYPES_BLOCK_ID: {
if (!hasValidControlBlock)
return error();
// The decls-and-types block is lazily loaded. Save the cursor and load
// any abbrev records at the start of the block.
DeclTypeCursor = cursor;
DeclTypeCursor.EnterSubBlock(DECLS_AND_TYPES_BLOCK_ID);
if (DeclTypeCursor.advance().Kind == llvm::BitstreamEntry::Error)
return error();
// With the main cursor, skip over the block and continue.
if (cursor.SkipBlock())
return error();
break;
}
case INDEX_BLOCK_ID: {
if (!hasValidControlBlock)
return error();