Skip to content

Commit eaceb46

Browse files
committed
Use the dynamic type of self in the expression evaluator.
This allows LLDB to resolve generic self types even if no type parameters are present (for example, because they were optimized out) because class objects and other entities carry all their dynamic type information in the *object*. rdar://problem/69020595
1 parent e161d5c commit eaceb46

File tree

9 files changed

+167
-40
lines changed

9 files changed

+167
-40
lines changed

lldb/include/lldb/Symbol/Type.h

+1
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ class SymbolFileType : public std::enable_shared_from_this<SymbolFileType>,
5656
Type *operator->() { return GetType(); }
5757

5858
Type *GetType();
59+
SymbolFile &GetSymbolFile() const { return m_symbol_file; }
5960

6061
protected:
6162
SymbolFile &m_symbol_file;

lldb/include/lldb/Symbol/Variable.h

+2
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ class Variable : public UserID, public std::enable_shared_from_this<Variable> {
6565

6666
lldb::ValueType GetScope() const { return m_scope; }
6767

68+
const RangeList &GetScopeRange() const { return m_scope_range; }
69+
6870
bool IsExternal() const { return m_external; }
6971

7072
bool IsArtificial() const { return m_artificial; }

lldb/source/Plugins/ExpressionParser/Swift/SwiftASTManipulator.cpp

+1-5
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "Plugins/TypeSystem/Swift/SwiftASTContext.h"
1616
#include "lldb/Expression/ExpressionParser.h"
1717
#include "lldb/Expression/ExpressionSourceCode.h"
18+
#include "lldb/Target/SwiftLanguageRuntime.h"
1819
#include "lldb/Target/Target.h"
1920
#include "lldb/Utility/ConstString.h"
2021
#include "lldb/Utility/Log.h"
@@ -1021,11 +1022,6 @@ GetPatternBindingForVarDecl(swift::VarDecl *var_decl,
10211022
return pattern_binding;
10221023
}
10231024

1024-
static inline swift::Type GetSwiftType(CompilerType type) {
1025-
return swift::Type(
1026-
reinterpret_cast<swift::TypeBase *>(type.GetOpaqueQualType()));
1027-
}
1028-
10291025
bool SwiftASTManipulator::AddExternalVariables(
10301026
llvm::MutableArrayRef<VariableInfo> variables) {
10311027
if (!IsValid())

lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionParser.cpp

+56-31
Original file line numberDiff line numberDiff line change
@@ -479,7 +479,7 @@ AddRequiredAliases(Block *block, lldb::StackFrameSP &stack_frame_sp,
479479
if (stack_frame_sp) {
480480
lldb::ValueObjectSP valobj_sp =
481481
stack_frame_sp->GetValueObjectForFrameVariable(self_var_sp,
482-
lldb::eNoDynamicValues);
482+
lldb::eDynamicCanRunTarget);
483483

484484
if (valobj_sp)
485485
self_type = valobj_sp->GetCompilerType();
@@ -604,7 +604,7 @@ static void AddVariableInfo(
604604
if (stack_frame_sp) {
605605
lldb::ValueObjectSP valobj_sp =
606606
stack_frame_sp->GetValueObjectForFrameVariable(variable_sp,
607-
lldb::eNoDynamicValues);
607+
lldb::eDynamicCanRunTarget);
608608

609609
if (!valobj_sp || valobj_sp->GetError().Fail()) {
610610
// Ignore the variable if we couldn't find its corresponding
@@ -628,12 +628,6 @@ static void AddVariableInfo(
628628
if (!target_type.IsValid())
629629
return;
630630

631-
// Resolve all archetypes in the variable type.
632-
if (stack_frame_sp)
633-
if (language_runtime)
634-
target_type = language_runtime->BindGenericTypeParameters(*stack_frame_sp,
635-
target_type);
636-
637631
// If we couldn't fully realize the type, then we aren't going
638632
// to get very far making a local out of it, so discard it here.
639633
Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_TYPES |
@@ -642,7 +636,7 @@ static void AddVariableInfo(
642636
if (log)
643637
log->Printf("Discarding local %s because we couldn't fully realize it, "
644638
"our best attempt was: %s.",
645-
name_cstr, target_type.GetTypeName().AsCString("<unknown>"));
639+
name_cstr, target_type.GetDisplayTypeName().AsCString("<unknown>"));
646640
return;
647641
}
648642

@@ -656,8 +650,27 @@ static void AddVariableInfo(
656650
static_cast<void *>(swift_type.getPointer()),
657651
static_cast<void *>(ast_context.GetASTContext()), s.c_str());
658652
}
653+
// A one-off clone of variable_sp with the type replaced by target_type.
654+
auto patched_variable_sp = std::make_shared<lldb_private::Variable>(
655+
0, variable_sp->GetName().GetCString(), "",
656+
std::make_shared<lldb_private::SymbolFileType>(
657+
*variable_sp->GetType()->GetSymbolFile(),
658+
std::make_shared<lldb_private::Type>(
659+
0, variable_sp->GetType()->GetSymbolFile(),
660+
variable_sp->GetType()->GetName(), llvm::None,
661+
variable_sp->GetType()->GetSymbolContextScope(), LLDB_INVALID_UID,
662+
Type::eEncodingIsUID, variable_sp->GetType()->GetDeclaration(),
663+
target_type, lldb_private::Type::ResolveState::Full,
664+
variable_sp->GetType()->GetPayload())),
665+
variable_sp->GetScope(), variable_sp->GetSymbolContextScope(),
666+
variable_sp->GetScopeRange(),
667+
const_cast<lldb_private::Declaration *>(&variable_sp->GetDeclaration()),
668+
variable_sp->LocationExpression(), variable_sp->IsExternal(),
669+
variable_sp->IsArtificial(),
670+
variable_sp->GetLocationIsConstantValueData(),
671+
variable_sp->IsStaticMember(), variable_sp->IsConstant());
659672
SwiftASTManipulatorBase::VariableMetadataSP metadata_sp(
660-
new VariableMetadataVariable(variable_sp));
673+
new VariableMetadataVariable(patched_variable_sp));
661674
SwiftASTManipulator::VariableInfo variable_info(
662675
target_type, ast_context.GetASTContext()->getIdentifier(overridden_name),
663676
metadata_sp,
@@ -917,6 +930,23 @@ CreateMainFile(SwiftASTContextForExpressions &swift_ast_context,
917930
return {buffer_id, filename.str()};
918931
}
919932

933+
/// Determine whether this type was defined inside an LLDB expression.
934+
template <typename TypeType> bool FromLLDBModuleImpl(TypeType *type) {
935+
if (auto *decl = type->getDecl())
936+
if (auto *module = decl->getModuleContext())
937+
return module->getName().str().startswith("__lldb_expr_");
938+
return false;
939+
};
940+
941+
/// Determine whether this type was defined inside an LLDB expression.
942+
static bool FromLLDBModule(swift::TypeBase *type) {
943+
if (auto *type_alias = llvm::dyn_cast<swift::TypeAliasType>(type))
944+
return FromLLDBModuleImpl(type_alias);
945+
if (auto *nominal = llvm::dyn_cast<swift::NominalType>(type))
946+
return FromLLDBModuleImpl(nominal);
947+
return false;
948+
}
949+
920950
/// Attempt to materialize one variable.
921951
static llvm::Optional<SwiftExpressionParser::SILVariableInfo>
922952
MaterializeVariable(SwiftASTManipulatorBase::VariableInfo &variable,
@@ -954,23 +984,7 @@ MaterializeVariable(SwiftASTManipulatorBase::VariableInfo &variable,
954984
}
955985
}
956986
} else {
957-
CompilerType actual_type(variable.GetType());
958-
auto orig_swift_type = GetSwiftType(actual_type);
959-
auto *swift_type = orig_swift_type->mapTypeOutOfContext().getPointer();
960-
actual_type = ToCompilerType(swift_type);
961-
lldb::StackFrameSP stack_frame_sp = stack_frame_wp.lock();
962-
if (swift_type->hasTypeParameter()) {
963-
if (stack_frame_sp && stack_frame_sp->GetThread() &&
964-
stack_frame_sp->GetThread()->GetProcess()) {
965-
auto *swift_runtime = SwiftLanguageRuntime::Get(
966-
stack_frame_sp->GetThread()->GetProcess());
967-
if (swift_runtime) {
968-
actual_type = swift_runtime->BindGenericTypeParameters(
969-
*stack_frame_sp, actual_type);
970-
}
971-
}
972-
}
973-
987+
CompilerType actual_type = variable.GetType();
974988
// Desugar '$lldb_context', etc.
975989
auto transformed_type = GetSwiftType(actual_type).transform(
976990
[](swift::Type t) -> swift::Type {
@@ -981,7 +995,21 @@ MaterializeVariable(SwiftASTManipulatorBase::VariableInfo &variable,
981995
}
982996
return t;
983997
});
984-
actual_type = ToCompilerType(transformed_type.getPointer());
998+
actual_type =
999+
ToCompilerType(transformed_type->mapTypeOutOfContext().getPointer());
1000+
// CompilerType return_ast_type =
1001+
// ToCompilerType(result_type->mapTypeOutOfContext());
1002+
auto *swift_ast_ctx =
1003+
llvm::cast<SwiftASTContext>(actual_type.GetTypeSystem());
1004+
1005+
// Currently the Swift runtime cannot resolve types that were
1006+
// defined in the expression evaluator. That's because we don't
1007+
// tell it about type metadata sections that were JIT-compiled
1008+
// by the expression evaluator. Until that is implemented, fall
1009+
// back to SwiftASTContext.
1010+
if (!FromLLDBModule(transformed_type.getPointer()))
1011+
actual_type =
1012+
swift_ast_ctx->GetTypeRefType(actual_type.GetOpaqueQualType());
9851013

9861014
if (is_result)
9871015
offset = materializer.AddResultVariable(
@@ -1009,9 +1037,6 @@ MaterializeVariable(SwiftASTManipulatorBase::VariableInfo &variable,
10091037
VariableMetadataVariable *variable_metadata =
10101038
static_cast<VariableMetadataVariable *>(variable.m_metadata.get());
10111039

1012-
// FIXME: It would be nice if we could do something like
1013-
// variable_metadata->m_variable_sp->SetType(variable.GetType())
1014-
// here.
10151040
offset = materializer.AddVariable(variable_metadata->m_variable_sp, error);
10161041

10171042
if (!error.Success()) {

lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.cpp

+54-4
Original file line numberDiff line numberDiff line change
@@ -1250,6 +1250,19 @@ bool Equivalent<llvm::Optional<uint64_t>>(llvm::Optional<uint64_t> l,
12501250
return false;
12511251
}
12521252

1253+
/// Version taylored to GetTypeBitAlign.
1254+
template <>
1255+
bool Equivalent<llvm::Optional<size_t>>(llvm::Optional<size_t> l,
1256+
llvm::Optional<size_t> r) {
1257+
if (l == r)
1258+
return true;
1259+
// Assume that any value is "better" than none.
1260+
if (l.hasValue() && !r.hasValue())
1261+
return true;
1262+
llvm::dbgs() << l << " != " << r << "\n";
1263+
return false;
1264+
}
1265+
12531266
} // namespace
12541267
#endif
12551268

@@ -1615,13 +1628,35 @@ TypeSystemSwiftTypeRef::GetArrayElementType(opaque_compiler_type_t type,
16151628
VALIDATE_AND_RETURN(impl, GetArrayElementType, type,
16161629
(ReconstructType(type), nullptr, exe_scope));
16171630
}
1631+
1632+
/// Determine wether this demangle tree contains an unresolved type alias.
1633+
static bool ContainsUnresolvedTypeAlias(swift::Demangle::NodePointer node) {
1634+
if (!node)
1635+
return false;
1636+
1637+
if (node->getKind() == swift::Demangle::Node::Kind::TypeAlias)
1638+
return true;
1639+
1640+
for (swift::Demangle::NodePointer child : *node)
1641+
if (ContainsUnresolvedTypeAlias(child))
1642+
return true;
1643+
1644+
return false;
1645+
}
1646+
16181647
CompilerType
16191648
TypeSystemSwiftTypeRef::GetCanonicalType(opaque_compiler_type_t type) {
16201649
auto impl = [&]() {
16211650
using namespace swift::Demangle;
16221651
Demangler dem;
16231652
NodePointer canonical =
16241653
GetCanonicalDemangleTree(m_swift_ast_context, dem, AsMangledName(type));
1654+
if (ContainsUnresolvedTypeAlias(canonical)) {
1655+
// If this is a typealias defined in the expression evaluator,
1656+
// then we don't have debug info to resolve it from.
1657+
CompilerType ast_type = ReconstructType({this, type}).GetCanonicalType();
1658+
return GetTypeFromMangledTypename(ast_type.GetMangledTypeName());
1659+
}
16251660
ConstString mangled(mangleNode(canonical));
16261661
return GetTypeFromMangledTypename(mangled);
16271662
};
@@ -1750,9 +1785,17 @@ TypeSystemSwiftTypeRef::GetBitSize(opaque_compiler_type_t type,
17501785
AsMangledName(type));
17511786
return {};
17521787
}
1788+
// The hot code path is to ask the Swift runtime for the size.
17531789
if (auto *runtime =
1754-
SwiftLanguageRuntime::Get(exe_scope->CalculateProcess()))
1755-
return runtime->GetBitSize({this, type}, exe_scope);
1790+
SwiftLanguageRuntime::Get(exe_scope->CalculateProcess())) {
1791+
if (auto result = runtime->GetBitSize({this, type}, exe_scope))
1792+
return result;
1793+
// If this is an expression context, perhaps the type was
1794+
// defined in the expression. In that case we don't have debug
1795+
// info for it, so defer to SwiftASTContext.
1796+
if (llvm::isa<SwiftASTContextForExpressions>(m_swift_ast_context))
1797+
return ReconstructType({this, type}).GetBitSize(exe_scope);
1798+
}
17561799

17571800
// If there is no process, we can still try to get the static size
17581801
// information out of DWARF. Because it is stored in the Type
@@ -2078,8 +2121,15 @@ TypeSystemSwiftTypeRef::GetTypeBitAlign(opaque_compiler_type_t type,
20782121
return {};
20792122
}
20802123
if (auto *runtime =
2081-
SwiftLanguageRuntime::Get(exe_scope->CalculateProcess()))
2082-
return runtime->GetBitAlignment({this, type}, exe_scope);
2124+
SwiftLanguageRuntime::Get(exe_scope->CalculateProcess())) {
2125+
if (auto result = runtime->GetBitAlignment({this, type}, exe_scope))
2126+
return result;
2127+
// If this is an expression context, perhaps the type was
2128+
// defined in the expression. In that case we don't have debug
2129+
// info for it, so defer to SwiftASTContext.
2130+
if (llvm::isa<SwiftASTContextForExpressions>(m_swift_ast_context))
2131+
return ReconstructType({this, type}).GetTypeBitAlign(exe_scope);
2132+
}
20832133

20842134
// If there is no process, we can still try to get the static
20852135
// alignment information out of DWARF. Because it is stored in the

lldb/source/Target/SwiftLanguageRuntimeDynamicTypeResolution.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -2141,6 +2141,9 @@ SwiftLanguageRuntimeImpl::GetTypeInfo(CompilerType type,
21412141
if (!ts)
21422142
return nullptr;
21432143

2144+
// Resolve all type aliases.
2145+
type = type.GetCanonicalType();
2146+
21442147
// Resolve all generic type parameters in the type for the current
21452148
// frame. Archetype binding has to happen in the scratch context,
21462149
// so we lock it while we are in this function.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
SWIFT_SOURCES := main.swift
2+
SWIFTFLAGS_EXTRAS := -O
3+
4+
include Makefile.rules
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import lldb
2+
from lldbsuite.test.lldbtest import *
3+
from lldbsuite.test.decorators import *
4+
import lldbsuite.test.lldbutil as lldbutil
5+
import unittest2
6+
7+
8+
class SwiftGenericClassTest(TestBase):
9+
10+
mydir = TestBase.compute_mydir(__file__)
11+
12+
def test(self):
13+
"""Tests that a generic class type can be resolved from the instance metadata alone"""
14+
self.build()
15+
(target, process, thread, breakpoint) = lldbutil.run_to_source_breakpoint(self,
16+
"break here", lldb.SBFileSpec("main.swift"))
17+
18+
self.expect("frame variable -d run self",
19+
substrs=["a.F<Int>", "23", "42", "128", "256"])
20+
self.expect("expr -d run -- self",
21+
substrs=["a.F<Int>", "23", "42", "128", "256"])
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
public class F<A> {
2+
let a : A
3+
var b = 42
4+
var c = 128
5+
var d = 256
6+
public init(_ val : A) { a = val }
7+
}
8+
9+
protocol P {
10+
func method()
11+
}
12+
extension F : P {
13+
@inline(never) func method() {
14+
print("break here \(b)")
15+
}
16+
}
17+
18+
// Defeat type specialization.
19+
@inline(never) func getF() -> P {
20+
return F<Int>(23)
21+
}
22+
23+
let obj = getF()
24+
obj.method()
25+

0 commit comments

Comments
 (0)