mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[serialization] Hook up a module loader that just builds a TranslationUnit.
The writer stores the paths to the .swift files, the reader just loads those .swift files. Fun! No version validation yet. No separate ModuleReader class yet. No use of the SerializedModule architecture yet, except for creating a dummy module when the .sm file is corrupted. Swift SVN r5164
This commit is contained in:
@@ -12,11 +12,13 @@
|
||||
|
||||
#include "swift/Serialization/SerializedModuleLoader.h"
|
||||
#include "ModuleFormat.h"
|
||||
#include "swift/Subsystems.h"
|
||||
#include "swift/AST/AST.h"
|
||||
#include "swift/AST/Component.h"
|
||||
#include "swift/AST/Diagnostics.h"
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/Bitcode/BitstreamReader.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
#include "llvm/Support/SourceMgr.h"
|
||||
@@ -35,22 +37,24 @@ public:
|
||||
return DC->getContextKind() == DeclContextKind::SerializedModule;
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::pair<Identifier, SourceLoc> AccessPathElem;
|
||||
}
|
||||
|
||||
// FIXME: Copied from SourceLoader. Not bothering to fix until we decide that
|
||||
// the source loader search path should be the same as the module loader search
|
||||
// path.
|
||||
static llvm::error_code findModule(ASTContext &ctx, StringRef moduleID,
|
||||
SourceLoc importLoc,
|
||||
static llvm::error_code findModule(ASTContext &ctx, AccessPathElem moduleID,
|
||||
llvm::OwningPtr<llvm::MemoryBuffer> &buffer){
|
||||
llvm::SmallString<64> moduleFilename(moduleID);
|
||||
llvm::SmallString<64> moduleFilename(moduleID.first.str());
|
||||
moduleFilename += ".sm";
|
||||
|
||||
llvm::SmallString<128> inputFilename;
|
||||
|
||||
// First, search in the directory corresponding to the import location.
|
||||
// FIXME: This screams for a proper FileManager abstraction.
|
||||
int currentBufferID = ctx.SourceMgr.FindBufferContainingLoc(importLoc.Value);
|
||||
llvm::SMLoc rawLoc = moduleID.second.Value;
|
||||
int currentBufferID = ctx.SourceMgr.FindBufferContainingLoc(rawLoc);
|
||||
if (currentBufferID >= 0) {
|
||||
const llvm::MemoryBuffer *importingBuffer
|
||||
= ctx.SourceMgr.getBufferInfo(currentBufferID).Buffer;
|
||||
@@ -82,10 +86,60 @@ static llvm::error_code findModule(ASTContext &ctx, StringRef moduleID,
|
||||
return err;
|
||||
}
|
||||
|
||||
static Module *makeTU(ASTContext &ctx, AccessPathElem moduleID,
|
||||
ArrayRef<StringRef> inputPaths) {
|
||||
Component *comp = new (ctx.Allocate<Component>(1)) Component();
|
||||
TranslationUnit *TU = new (ctx) TranslationUnit(moduleID.first, comp, ctx,
|
||||
/*IsMainModule=*/false,
|
||||
/*IsReplModule=*/false);
|
||||
|
||||
ctx.LoadedModules[moduleID.first.str()] = TU;
|
||||
|
||||
std::vector<unsigned> BufferIDs;
|
||||
for (auto &path : inputPaths) {
|
||||
// Open the input file.
|
||||
llvm::OwningPtr<llvm::MemoryBuffer> InputFile;
|
||||
if (llvm::MemoryBuffer::getFileOrSTDIN(path, InputFile))
|
||||
return nullptr;
|
||||
|
||||
// Transfer ownership of the MemoryBuffer to the SourceMgr.
|
||||
// FIXME: include location
|
||||
llvm::SMLoc rawLoc = moduleID.second.Value;
|
||||
BufferIDs.push_back(ctx.SourceMgr.AddNewSourceBuffer(InputFile.take(),
|
||||
rawLoc));
|
||||
}
|
||||
|
||||
for (auto &BufferID : BufferIDs) {
|
||||
unsigned BufferOffset = 0;
|
||||
const llvm::MemoryBuffer *Buffer =
|
||||
ctx.SourceMgr.getMemoryBuffer(BufferID);
|
||||
do {
|
||||
parseIntoTranslationUnit(TU, BufferID, &BufferOffset, 0, /*SIL=*/nullptr);
|
||||
} while (BufferOffset != Buffer->getBufferSize());
|
||||
}
|
||||
|
||||
performNameBinding(TU);
|
||||
performTypeChecking(TU);
|
||||
|
||||
return TU;
|
||||
}
|
||||
|
||||
|
||||
Module *SerializedModuleLoader::error(AccessPathElem moduleID) {
|
||||
Ctx.Diags.diagnose(moduleID.second, diag::serialization_malformed_module);
|
||||
|
||||
// Return a dummy module to avoid future errors.
|
||||
auto comp = new (Ctx.Allocate<Component>(1)) Component();
|
||||
auto module = new (Ctx) SerializedModule(Ctx, *this, moduleID.first, comp);
|
||||
|
||||
Ctx.LoadedModules[moduleID.first.str()] = module;
|
||||
return module;
|
||||
}
|
||||
|
||||
Module *SerializedModuleLoader::loadModule(SourceLoc importLoc,
|
||||
Module::AccessPathTy path) {
|
||||
using namespace serialization;
|
||||
|
||||
Module *SerializedModuleLoader::loadModule(
|
||||
SourceLoc importLoc,
|
||||
ArrayRef<std::pair<Identifier, SourceLoc>> path) {
|
||||
// FIXME: Swift submodules?
|
||||
if (path.size() > 1)
|
||||
return nullptr;
|
||||
@@ -93,8 +147,7 @@ Module *SerializedModuleLoader::loadModule(
|
||||
auto moduleID = path[0];
|
||||
|
||||
llvm::OwningPtr<llvm::MemoryBuffer> inputFile;
|
||||
if (llvm::error_code err = findModule(Ctx, moduleID.first.str(),
|
||||
moduleID.second, inputFile)) {
|
||||
if (llvm::error_code err = findModule(Ctx, moduleID, inputFile)) {
|
||||
if (err.value() != llvm::errc::no_such_file_or_directory) {
|
||||
Ctx.Diags.diagnose(moduleID.second, diag::sema_opening_import,
|
||||
moduleID.first.str(), err.message());
|
||||
@@ -104,16 +157,85 @@ Module *SerializedModuleLoader::loadModule(
|
||||
}
|
||||
|
||||
assert(inputFile);
|
||||
if (!inputFile->getBuffer().startswith(serialization::SIGNATURE)) {
|
||||
// FIXME: Diagnose malformed module? Right now we silently skip it and
|
||||
// continue searching.
|
||||
return nullptr;
|
||||
auto start =
|
||||
reinterpret_cast<const unsigned char *>(inputFile->getBufferStart());
|
||||
auto end =
|
||||
reinterpret_cast<const unsigned char *>(inputFile->getBufferEnd());
|
||||
llvm::BitstreamReader reader(start, end);
|
||||
llvm::BitstreamCursor cursor(reader);
|
||||
|
||||
for (unsigned char byte : SIGNATURE) {
|
||||
if (cursor.AtEndOfStream() || cursor.Read(8) != byte)
|
||||
return error(moduleID);
|
||||
}
|
||||
|
||||
// For now, treat all separate modules as unique components.
|
||||
auto comp = new (Ctx.Allocate<Component>(1)) Component();
|
||||
auto module = new (Ctx) SerializedModule(Ctx, *this, moduleID.first, comp);
|
||||
// Future-proofing: make sure we validate the control block before we try to
|
||||
// read any other blocks.
|
||||
bool hasValidControlBlock = false;
|
||||
|
||||
Ctx.LoadedModules[module->Name.str()] = module;
|
||||
// FIXME: Hack to get the interesting case up and running.
|
||||
SmallVector<uint64_t, 64> scratch;
|
||||
SmallVector<StringRef, 4> inputFilePaths;
|
||||
|
||||
auto topLevelEntry = cursor.advance();
|
||||
while (topLevelEntry.Kind == llvm::BitstreamEntry::SubBlock) {
|
||||
switch (topLevelEntry.ID) {
|
||||
case llvm::bitc::BLOCKINFO_BLOCK_ID:
|
||||
if (cursor.ReadBlockInfoBlock())
|
||||
return error(moduleID);
|
||||
break;
|
||||
|
||||
case CONTROL_BLOCK_ID:
|
||||
// FIXME: Actually validate the control block.
|
||||
if (cursor.SkipBlock())
|
||||
return error(moduleID);
|
||||
hasValidControlBlock = true;
|
||||
break;
|
||||
|
||||
case INPUT_BLOCK_ID: {
|
||||
cursor.EnterSubBlock(INPUT_BLOCK_ID);
|
||||
// FIXME: Hack to get the interesting case up and running.
|
||||
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());
|
||||
inputFilePaths.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(moduleID);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
// Unknown top-level block, possibly for use by a future version of the
|
||||
// module format.
|
||||
if (cursor.SkipBlock())
|
||||
return error(moduleID);
|
||||
break;
|
||||
}
|
||||
|
||||
topLevelEntry = cursor.advance(llvm::BitstreamCursor::AF_DontPopBlockAtEnd);
|
||||
}
|
||||
|
||||
if (topLevelEntry.Kind != llvm::BitstreamEntry::EndBlock)
|
||||
return error(moduleID);
|
||||
|
||||
// FIXME: At least /pretend/ to be a LoadedModule.
|
||||
auto module = makeTU(Ctx, moduleID, inputFilePaths);
|
||||
return module;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user