mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
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:
@@ -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*>())
|
||||
|
||||
Reference in New Issue
Block a user