Serialize local types and provide a lookup API

rdar://problem/18295292

Locally scoped type declarations were previously not serialized into the
module, which meant that the debugger couldn't reason about the
structure of instances of those types.

Introduce a new mangling for local types:
[file basename MD5][counter][identifier]
This allows the demangle node's data to be used directly for lookup
without having to backtrack in the debugger.

Local decls are now serialized into a LOCAL_TYPE_DECLS table in the
module, which acts as the backing hash table for looking up
[file basename MD5][counter][identifier] -> DeclID mappings.

New tests:
* swift-ide-test mode for testing the demangle/lookup/mangle lifecycle
of a module that contains local decls
* mangling
* module merging with local decls

Swift SVN r24426
This commit is contained in:
David Farler
2015-01-14 22:08:47 +00:00
parent e56448b1ee
commit fab3d491d9
44 changed files with 1177 additions and 194 deletions

View File

@@ -21,6 +21,7 @@
#include "swift/AST/DiagnosticsSema.h"
#include "swift/AST/LazyResolver.h"
#include "swift/AST/LinkLibrary.h"
#include "swift/AST/Mangle.h"
#include "swift/AST/ModuleLoader.h"
#include "swift/AST/NameLookup.h"
#include "swift/AST/ReferencedNameTracker.h"
@@ -32,10 +33,7 @@
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/TinyPtrVector.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/MD5.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/SaveAndRestore.h"
@@ -142,7 +140,7 @@ public:
void lookupValue(AccessPathTy AccessPath, DeclName Name,
NLKind LookupKind, SmallVectorImpl<ValueDecl*> &Result);
void lookupVisibleDecls(AccessPathTy AccessPath,
VisibleDeclConsumer &Consumer,
NLKind LookupKind);
@@ -432,6 +430,18 @@ void Module::lookupValue(AccessPathTy AccessPath, DeclName Name,
FORWARD(lookupValue, (AccessPath, Name, LookupKind, Result));
}
TypeDecl *Module::lookupLocalType(StringRef FileHash,
unsigned LocalDiscriminator,
StringRef Name) const {
for(auto file : getFiles()) {
auto localTypeDecl = file->lookupLocalType(FileHash, LocalDiscriminator,
Name);
if (localTypeDecl)
return localTypeDecl;
}
return nullptr;
}
void Module::lookupMember(SmallVectorImpl<ValueDecl*> &results,
DeclContext *container, DeclName name,
Identifier privateDiscriminator) const {
@@ -443,6 +453,7 @@ void Module::lookupMember(SmallVectorImpl<ValueDecl*> &results,
case DeclContextKind::Initializer:
case DeclContextKind::TopLevelCodeDecl:
case DeclContextKind::AbstractFunctionDecl:
case DeclContextKind::LocalDecl:
llvm_unreachable("This context does not support lookup.");
case DeclContextKind::FileUnit:
@@ -594,10 +605,18 @@ void Module::getTopLevelDecls(SmallVectorImpl<Decl*> &Results) const {
FORWARD(getTopLevelDecls, (Results));
}
void Module::getLocalTypeDecls(SmallVectorImpl<Decl*> &Results) const {
FORWARD(getLocalTypeDecls, (Results));
}
void SourceFile::getTopLevelDecls(SmallVectorImpl<Decl*> &Results) const {
Results.append(Decls.begin(), Decls.end());
}
void SourceFile::getLocalTypeDecls(SmallVectorImpl<Decl*> &Results) const {
Results.append(LocalTypeDecls.begin(), LocalTypeDecls.end());
}
void Module::getDisplayDecls(SmallVectorImpl<Decl*> &Results) const {
// FIXME: Should this do extra access control filtering?
FORWARD(getDisplayDecls, (Results));
@@ -1373,6 +1392,48 @@ bool FileUnit::forAllVisibleModules(
return true;
}
Identifier FileUnit::getDiscriminator() const {
if (Discriminator.get() != nullptr)
return Discriminator;
StringRef name = getFilename();
if (name.empty()) {
assert(1 == std::count_if(getParentModule()->getFiles().begin(),
getParentModule()->getFiles().end(),
[](const FileUnit *FU) -> bool {
return isa<SourceFile>(FU) && FU->getFilename().empty();
}) && "can't promise uniqueness if multiple source files are nameless");
// We still need a discriminator, so keep going.
}
// Use a hash of the basename of the source file as our discriminator.
// This keeps us from leaking information about the original filename
// while still providing uniqueness. Using the basename makes the
// discriminator invariant across source checkout locations.
// FIXME: Use a faster hash here? We don't need security, just uniqueness.
llvm::MD5 hash;
hash.update(getParentModule()->Name.str());
hash.update(llvm::sys::path::filename(name));
llvm::MD5::MD5Result result;
hash.final(result);
// Make sure the whole thing is a valid identifier.
SmallString<33> buffer{"_"};
// Write the hash as a hex string.
// FIXME: This should go into llvm/ADT/StringExtras.h.
// FIXME: And there are more compact ways to encode a 16-byte value.
buffer.reserve(buffer.size() + 2*llvm::array_lengthof(result));
for (uint8_t byte : result) {
buffer.push_back(llvm::hexdigit(byte >> 4, /*lowercase=*/false));
buffer.push_back(llvm::hexdigit(byte & 0xF, /*lowercase=*/false));
}
Discriminator = getASTContext().getIdentifier(buffer);
return Discriminator;
}
void Module::collectLinkLibraries(LinkLibraryCallback callback) {
// FIXME: The proper way to do this depends on the decls used.
FORWARD(collectLinkLibraries, (callback));
@@ -1535,46 +1596,7 @@ ArtificialMainKind SourceFile::getArtificialMainKind() const {
Identifier
SourceFile::getDiscriminatorForPrivateValue(const ValueDecl *D) const {
assert(D->getDeclContext()->getModuleScopeContext() == this);
if (!PrivateDiscriminator.empty())
return PrivateDiscriminator;
StringRef name = getFilename();
if (name.empty()) {
assert(1 == std::count_if(getParentModule()->getFiles().begin(),
getParentModule()->getFiles().end(),
[](const FileUnit *FU) -> bool {
return isa<SourceFile>(FU) && cast<SourceFile>(FU)->getFilename().empty();
}) && "can't promise uniqueness if multiple source files are nameless");
// We still need a discriminator, so keep going.
}
// Use a hash of the basename of the source file as our discriminator.
// This keeps us from leaking information about the original filename
// while still providing uniqueness. Using the basename makes the
// discriminator invariant across source checkout locations.
// FIXME: Use a faster hash here? We don't need security, just uniqueness.
llvm::MD5 hash;
hash.update(getParentModule()->Name.str());
hash.update(llvm::sys::path::filename(name));
llvm::MD5::MD5Result result;
hash.final(result);
// Make sure the whole thing is a valid identifier.
SmallString<33> buffer{"_"};
// Write the hash as a hex string.
// FIXME: This should go into llvm/ADT/StringExtras.h.
// FIXME: And there are more compact ways to encode a 16-byte value.
buffer.reserve(buffer.size() + 2*llvm::array_lengthof(result));
for (uint8_t byte : result) {
buffer.push_back(llvm::hexdigit(byte >> 4, /*lowercase=*/false));
buffer.push_back(llvm::hexdigit(byte & 0xF, /*lowercase=*/false));
}
PrivateDiscriminator = getASTContext().getIdentifier(buffer);
return PrivateDiscriminator;
return getDiscriminator();
}
TypeRefinementContext *SourceFile::getTypeRefinementContext() {
@@ -1590,10 +1612,6 @@ void *FileUnit::operator new(size_t Bytes, ASTContext &C, unsigned Alignment) {
return C.Allocate(Bytes, Alignment);
}
StringRef LoadedFile::getFilename() const {
return "";
}
StringRef ModuleEntity::getName() const {
assert(!Mod.isNull());
if (auto SwiftMod = Mod.dyn_cast<const Module*>())