Files
swift-mirror/lib/Serialization/ModuleFile.cpp
Jordan Rose 965035dc2a [serialization] Load the decl and type offset arrays from the module.
...but don't do anything with them yet. This does check that they're being
correctly serialized, though.

This introduces a new ADT, PointerIntUnion, which like PointerUnion is an
efficient variant type using the lowest bit of data as a discriminator.
By default, the union can store any pointer-bits-minus-one-sized integer,
but both the integer type and the underlying storage type can be
customized.

Swift SVN r5321
2013-05-25 01:34:52 +00:00

188 lines
5.5 KiB
C++

//===--- ModuleFile.cpp - Loading a serialized module -----------*- c++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#include "ModuleFile.h"
#include "ModuleFormat.h"
#include "llvm/Support/MemoryBuffer.h"
using namespace swift;
using namespace swift::serialization;
static ModuleStatus
validateControlBlock(llvm::BitstreamCursor &cursor,
llvm::SmallVectorImpl<uint64_t> &scratch) {
// The control block is malformed until we've at least read a major version
// number.
ModuleStatus result = ModuleStatus::Malformed;
auto next = cursor.advance();
while (next.Kind != llvm::BitstreamEntry::EndBlock) {
if (next.Kind == llvm::BitstreamEntry::Error)
return ModuleStatus::Malformed;
if (next.Kind == llvm::BitstreamEntry::SubBlock) {
// Unknown metadata sub-block, possibly for use by a future version of the
// module format.
if (cursor.SkipBlock())
return ModuleStatus::Malformed;
next = cursor.advance();
continue;
}
scratch.clear();
StringRef blobData;
unsigned kind = cursor.readRecord(next.ID, scratch, &blobData);
switch (kind) {
case control_block::METADATA: {
uint16_t versionMajor = scratch[0];
if (versionMajor > VERSION_MAJOR)
return ModuleStatus::FormatTooNew;
result = ModuleStatus::Valid;
break;
}
default:
// Unknown metadata record, possibly for use by a future version of the
// module format.
break;
}
next = cursor.advance();
}
return result;
}
ModuleFile::ModuleFile(llvm::OwningPtr<llvm::MemoryBuffer> &&input)
: InputFile(std::move(input)),
InputReader(reinterpret_cast<const uint8_t *>(InputFile->getBufferStart()),
reinterpret_cast<const uint8_t *>(InputFile->getBufferEnd())),
Status(ModuleStatus::Valid) {
llvm::BitstreamCursor cursor{InputReader};
for (unsigned char byte : SIGNATURE) {
if (cursor.AtEndOfStream() || cursor.Read(8) != byte)
return error();
}
// Future-proofing: make sure we validate the control block before we try to
// read any other blocks.
bool hasValidControlBlock = false;
SmallVector<uint64_t, 64> scratch;
auto topLevelEntry = cursor.advance();
while (topLevelEntry.Kind == llvm::BitstreamEntry::SubBlock) {
switch (topLevelEntry.ID) {
case llvm::bitc::BLOCKINFO_BLOCK_ID:
if (cursor.ReadBlockInfoBlock())
return error();
break;
case CONTROL_BLOCK_ID: {
cursor.EnterSubBlock(CONTROL_BLOCK_ID);
ModuleStatus err = validateControlBlock(cursor, scratch);
if (err != ModuleStatus::Valid)
return error(err);
hasValidControlBlock = true;
break;
}
case INPUT_BLOCK_ID: {
if (!hasValidControlBlock)
return error();
cursor.EnterSubBlock(INPUT_BLOCK_ID);
auto next = cursor.advance();
while (next.Kind == llvm::BitstreamEntry::Record) {
scratch.clear();
StringRef blobData;
unsigned kind = cursor.readRecord(next.ID, scratch, &blobData);
switch (kind) {
case input_block::SOURCE_FILE:
assert(scratch.empty());
SourcePaths.push_back(blobData);
break;
default:
// Unknown input kind, possibly for use by a future version of the
// module format.
// FIXME: Should we warn about this?
break;
}
next = cursor.advance();
}
if (next.Kind != llvm::BitstreamEntry::EndBlock)
return error();
break;
}
case INDEX_BLOCK_ID: {
if (!hasValidControlBlock)
return error();
cursor.EnterSubBlock(INDEX_BLOCK_ID);
auto next = cursor.advanceSkippingSubblocks();
while (next.Kind == llvm::BitstreamEntry::Record) {
scratch.clear();
StringRef blobData;
unsigned kind = cursor.readRecord(next.ID, scratch, &blobData);
switch (kind) {
case index_block::DECL_OFFSETS:
assert(blobData.empty());
// FIXME: Use proper BCRecordLayout for this.
Decls.assign(scratch.begin()+1, scratch.end());
break;
case index_block::TYPE_OFFSETS:
assert(blobData.empty());
// FIXME: Use proper BCRecordLayout for this.
Types.assign(scratch.begin()+1, scratch.end());
break;
default:
// Unknown index kind, which this version of the compiler won't use.
break;
}
next = cursor.advanceSkippingSubblocks();
}
if (next.Kind != llvm::BitstreamEntry::EndBlock)
return error();
break;
}
case FALL_BACK_TO_TRANSLATION_UNIT_ID:
// This is a bring-up hack and will eventually go away.
Status = ModuleStatus::FallBackToTranslationUnit;
break;
default:
// Unknown top-level block, possibly for use by a future version of the
// module format.
if (cursor.SkipBlock())
return error();
break;
}
topLevelEntry = cursor.advance(llvm::BitstreamCursor::AF_DontPopBlockAtEnd);
}
if (topLevelEntry.Kind != llvm::BitstreamEntry::EndBlock)
return error();
}