Skip to content

Introduce a DWARFImporter delegate that can look up clang::Decls by name #26493

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 7, 2019

Conversation

adrian-prantl
Copy link
Contributor

Traditionally a serialized binary Swift module (as used in debug info)
can only be imported if all of its Clang dependencies can be imported
from source.

  • Swift's ClangImporter imports Clang modules by converting Clang AST
    types into Swift AST types.

  • LLDB knows how to find Clang types in DWARF or other debug info and
    can synthesize a Clang AST from that information.

This patch introduces a DWARFImporter delegate that is implemented by
LLDB to connect these two components. With this, a Clang type can be
found (by name) in the debug info and handed over to ClangImporter to
create a Swift type from it. This path has lower fidelity than
importing the Clang modules from source, since it is missing out on
Swiftication annotations and other metadata that is not serialized in
DWARF, but it's invaluable as a fallback mechanism for the debugger
when source code for the Clang modules isn't available or the modules
are otherwise not buildable.

rdar://problem/49233932

@adrian-prantl
Copy link
Contributor Author

adrian-prantl commented Aug 5, 2019

test with apple/swift-lldb#1848
@swift-ci test

@swift-ci
Copy link
Contributor

swift-ci commented Aug 5, 2019

Build failed
Swift Test Linux Platform
Git Sha - 93ddfdb7248bcee2c4081f015a1150816316b19e

@adrian-prantl
Copy link
Contributor Author

test with apple/swift-lldb#1848
@swift-ci smoke test

@adrian-prantl
Copy link
Contributor Author

test with apple/swift-lldb#1848
@swift-ci smoke test

1 similar comment
@adrian-prantl
Copy link
Contributor Author

test with apple/swift-lldb#1848
@swift-ci smoke test

@adrian-prantl
Copy link
Contributor Author

test with apple/swift-lldb#1848
@swift-ci smoke test

@adrian-prantl adrian-prantl force-pushed the 49233932 branch 2 times, most recently from d58d4a1 to d8accb8 Compare August 6, 2019 23:49
@adrian-prantl
Copy link
Contributor Author

test with apple/swift-lldb#1848
@swift-ci smoke test

…ame.

Traditionally a serialized binary Swift module (as used in debug info)
can only be imported if all of its Clang dependencies can be imported
*from source*.

- Swift's ClangImporter imports Clang modules by converting Clang AST
  types into Swift AST types.

- LLDB knows how to find Clang types in DWARF or other debug info and
  can synthesize a Clang AST from that information.

This patch introduces a DWARFImporter delegate that is implemented by
LLDB to connect these two components. With this, a Clang type can be
found (by name) in the debug info and handed over to ClangImporter to
create a Swift type from it.  This path has lower fidelity than
importing the Clang modules from source, since it is missing out on
Swiftication annotations and other metadata that is not serialized in
DWARF, but it's invaluable as a fallback mechanism for the debugger
when source code for the Clang modules isn't available or the modules
are otherwise not buildable.

rdar://problem/49233932
@adrian-prantl
Copy link
Contributor Author

test with apple/swift-lldb#1848
@swift-ci smoke test

@@ -58,6 +60,30 @@ class ClangModuleLoader : public ModuleLoader {
const DeclContext *overlayDC,
const DeclContext *importedDC) = 0;

/// Look for declarations associated with the given name.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These virtual methods are necessary to break a cyclic dependency on Linux.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain further? I'm not sure why there'd be a cycle.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem only existed on Linux, and no amount of duplicating llink libraries in the CMakeLists would make it go away. Part of the problem was that ASTDemangler in libAST.a had an explicit cast and a method call to DWARFImporter and libDWARFImporter.a in turn depends on libAST. I do not understand why this wasn't also a problem with ClangImporter, which effectively does the same thing. If you are concerned about the interface/performance I can try a little harder, but I also think having a common interface in the common base class of ClangImporter and DWARFImporter is actually good.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ASTDemangler definitely should not be calling DWARFImporter directly, and I'm sorry I missed that part. Let's come up with a better way to let DWARFImporter intervene in looking up Clang types.

@adrian-prantl adrian-prantl merged commit 206994c into swiftlang:master Aug 7, 2019
///
/// If there is no Clang module loader, returns a null pointer.
/// The loader is owned by the AST context.
ClangModuleLoader *getDWARFModuleLoader() const;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you get rid of this? The Clang importer is special because the Swift compiler has to use it for other things. It would definitely be bad if we had to start special-casing the DWARF loader throughout the compiler as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The only use of this method is in ASTDemangler.cpp in ASTBuilder::findForeignTypeDecl(), which tries the DWARFImporter after the ClangImporter failed. We could changing ASTContext::getClangModuleLoader() to return a list of ClangModuleLoaders sorted by the order in which they should be queried. Would that be better?

/// Clang AST to ClangImporter to import the type into Swift.
class DWARFImporterDelegate {
public:
virtual ~DWARFImporterDelegate() {}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: = default allows a tiny bit more optimization in some cases.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ClangImporter::lookupTypeDecl(StringRef rawName, ClangTypeKind kind,
llvm::function_ref<void(TypeDecl*)> receiver) {
static Optional<ClangTypeKind>
getClangTypeKindForNodeKind(Demangle::Node::Kind kind) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really don't like moving this. Why is it the importer's responsibility to resolve manglings?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is basically based on a misunderstanding on my end that I since dicovered and I can revert this change. Because of how ClangTypeKind folds both enums and structs into ClangTypeKind::Tag I was afraid the we'd be loosing information that could make the type search in DWARF more accurate. Later I discovered that structs, unions and many enums are all mangled as structs anyway, so this point doesn't hold any more. I'll prepare a patch to undo this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

enum class ClangTypeKind {
  Typedef,
  ObjCClass = Typedef,
  /// Structs, enums, and unions.
  Tag,
  ObjCProtocol,
}

Looks like we would be loosing the ability to distinguish between typedefs and ObjC classes, but that may not be such a big deal.

@@ -13,33 +13,37 @@
#include "swift/DWARFImporter/DWARFImporter.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/Module.h"
#include "clang/CodeGen/ObjectFilePCHContainerOperations.h"
#include "clang/Frontend/FrontendActions.h"
#include "../ClangImporter/ImporterImpl.h"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is very questionable. ClangImporter::Implementation isn't designed for reuse; the distribution of information between ClangImporter and ClangImporter::Implementation is basically "whatever's most convenient". If we need a common base class, let's factor that out and put it in the include/ folder.

@@ -178,9 +179,9 @@ class ClangImporter final : public ClangModuleLoader {
/// Note that this method does no filtering. If it finds the type in a loaded
/// module, it returns it. This is intended for use in reflection / debugging
/// contexts where access is not a problem.
void lookupRelatedEntity(StringRef clangName, ClangTypeKind kind,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is it okay to drop the "kind" parameter?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because it was not used by the function.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was deliberately an interface designed to handle arbitrary mangled names, even though we're not using the kind for anything yet.

@jrose-apple
Copy link
Contributor

Now that I see that the DWARF importer is injecting decls into the real Clang importer anyway (which makes sense because you want them all in one clang::ASTContext), maybe a new module loader wasn't ever the way to go. Maybe it'd be better for the Clang importer to have a DebugClient like the ASTContext does.

@adrian-prantl
Copy link
Contributor Author

Now that I see that the DWARF importer is injecting decls into the real Clang importer anyway (which makes sense because you want them all in one clang::ASTContext), maybe a new module loader wasn't ever the way to go. Maybe it'd be better for the Clang importer to have a DebugClient like the ASTContext does.

I think that this is doable. We can move DWARFImporter's mode of pretending it can import anything into a DWARFImporterDelegate callback handled by ClangImporter that only succeeds when a DWARFImporterDelegate is installed (and potentially actually checks whether we have DWARF for that module...). I'll go ahead and try this!

swift-ci pushed a commit that referenced this pull request Aug 13, 2019
Revert some unnecessary changes from #26493
@adrian-prantl
Copy link
Contributor Author

-> #26648

Turned out fairly clean.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants