Skip to content

Commit 3a02857

Browse files
Merge pull request #10148 from adrian-prantl/145301500
[lldb] Improve handling of indirect enums using reflection metadata
2 parents 1b5a84a + 06754a2 commit 3a02857

File tree

4 files changed

+211
-20
lines changed

4 files changed

+211
-20
lines changed

lldb/source/Plugins/LanguageRuntime/Swift/SwiftLanguageRuntimeDynamicTypeResolution.cpp

Lines changed: 83 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -815,6 +815,10 @@ SwiftLanguageRuntime::GetNumChildren(CompilerType type,
815815
return llvm::createStringError("could not typeref for " +
816816
type.GetMangledTypeName().GetString());
817817

818+
// Indirect enums.
819+
if (type.GetTypeInfo() & lldb::eTypeIsEnumeration)
820+
return 1;
821+
818822
// Existentials.
819823
if (size_t n = GetExistentialSyntheticChildren(ts, tr, ti).size())
820824
return n;
@@ -1029,6 +1033,8 @@ SwiftLanguageRuntime::GetIndexOfChildMemberWithName(
10291033
auto ts = type.GetTypeSystem().dyn_cast_or_null<TypeSystemSwiftTypeRef>();
10301034
if (!ts)
10311035
return {SwiftLanguageRuntime::eError, {}};
1036+
if (!exe_ctx)
1037+
return {SwiftLanguageRuntime::eError, {}};
10321038

10331039
using namespace swift::reflection;
10341040
// Try the static type metadata.
@@ -1086,6 +1092,29 @@ SwiftLanguageRuntime::GetIndexOfChildMemberWithName(
10861092
exe_ctx, omit_empty_base_classes,
10871093
child_indexes);
10881094
case ReferenceKind::Strong: {
1095+
// Indirect enums.
1096+
if (type.GetTypeInfo() & lldb::eTypeIsEnumeration) {
1097+
const swift::reflection::TypeRef *tr = nullptr;
1098+
auto ti_or_err = GetSwiftRuntimeTypeInfo(
1099+
type, exe_ctx->GetBestExecutionContextScope(), &tr);
1100+
if (!ti_or_err) {
1101+
LLDB_LOG_ERROR(GetLog(LLDBLog::Types), ti_or_err.takeError(),
1102+
"Could not get enum type info: {0}");
1103+
return {SwiftLanguageRuntime::eError, {}};
1104+
}
1105+
auto *eti = llvm::dyn_cast<EnumTypeInfo>(&*ti_or_err);
1106+
if (!eti) {
1107+
// This is probably a generic single-payload enum.
1108+
// Let's pretend we found it.
1109+
LLDB_LOG(GetLog(LLDBLog::Types),
1110+
"Presuming generic single-payload enum.");
1111+
child_indexes.push_back(0);
1112+
return {SwiftLanguageRuntime::eFound, child_indexes.size()};
1113+
}
1114+
return findFieldWithName(eti->getCases(), tr, name, true,
1115+
child_indexes);
1116+
}
1117+
10891118
ThreadSafeReflectionContext reflection_ctx = GetReflectionContext();
10901119
if (!reflection_ctx)
10911120
return {SwiftLanguageRuntime::eError, {}};
@@ -1197,6 +1226,47 @@ llvm::Expected<CompilerType> SwiftLanguageRuntime::GetChildCompilerTypeAtIndex(
11971226
return pack_element_type;
11981227
}
11991228

1229+
auto get_from_indirect_enum = [&]() -> llvm::Expected<CompilerType> {
1230+
ThreadSafeReflectionContext reflection_ctx = GetReflectionContext();
1231+
if (!reflection_ctx)
1232+
return llvm::createStringError("no reflection context");
1233+
// The indirect enum field should point to a closure context.
1234+
LLDBTypeInfoProvider tip(*this, &exe_ctx);
1235+
lldb::addr_t instance = ::MaskMaybeBridgedPointer(GetProcess(), pointer);
1236+
auto ti_or_err = reflection_ctx->GetTypeInfoFromInstance(
1237+
instance, &tip, ts->GetDescriptorFinder());
1238+
if (!ti_or_err) {
1239+
llvm::consumeError(ti_or_err.takeError());
1240+
return CompilerType();
1241+
}
1242+
auto *ti = &*ti_or_err;
1243+
if (auto *rti = llvm::dyn_cast<swift::reflection::RecordTypeInfo>(ti)) {
1244+
switch (rti->getRecordKind()) {
1245+
case swift::reflection::RecordKind::ClosureContext: {
1246+
auto &field = rti->getFields()[0];
1247+
auto *type_ref = field.TR;
1248+
language_flags |= TypeSystemSwift::LanguageFlags::eIsIndirectEnumCase;
1249+
child_byte_offset = field.Offset;
1250+
child_byte_size = field.TI.getSize();
1251+
return GetTypeFromTypeRef(*ts, type_ref);
1252+
}
1253+
case swift::reflection::RecordKind::Tuple: {
1254+
std::vector<TypeSystemSwift::TupleElement> elts;
1255+
for (auto &field : rti->getFields())
1256+
elts.emplace_back(ConstString(), GetTypeFromTypeRef(*ts, field.TR));
1257+
return ts->CreateTupleType(elts);
1258+
}
1259+
default:
1260+
return llvm::createStringError(
1261+
"unexpected kind of indirect record enum");
1262+
}
1263+
}
1264+
language_flags |= TypeSystemSwift::LanguageFlags::eIsIndirectEnumCase;
1265+
child_byte_offset = 0;
1266+
child_byte_size = ti->getSize();
1267+
return ts->GetBuiltinRawPointerType();
1268+
};
1269+
12001270
// The actual conversion from the FieldInfo record.
12011271
auto get_from_field_info =
12021272
[&](const swift::reflection::FieldInfo &field,
@@ -1225,27 +1295,16 @@ llvm::Expected<CompilerType> SwiftLanguageRuntime::GetChildCompilerTypeAtIndex(
12251295
CompilerType result;
12261296
if (tuple)
12271297
result = tuple->element_type;
1228-
else if (is_indirect_enum) {
1229-
ThreadSafeReflectionContext reflection_ctx = GetReflectionContext();
1230-
if (!reflection_ctx)
1231-
return llvm::createStringError("no reflection context");
1232-
// The indirect enum field should point to a closure context.
1233-
LLDBTypeInfoProvider tip(*this, &exe_ctx);
1234-
lldb::addr_t instance = ::MaskMaybeBridgedPointer(GetProcess(), pointer);
1235-
auto ti_or_err = reflection_ctx->GetTypeInfoFromInstance(
1236-
instance, &tip, ts->GetDescriptorFinder());
1237-
if (!ti_or_err)
1238-
return ti_or_err.takeError();
1239-
auto *ti = &*ti_or_err;
1240-
auto *rti = llvm::dyn_cast_or_null<swift::reflection::RecordTypeInfo>(ti);
1241-
if (rti->getFields().size() < 1)
1242-
return llvm::createStringError("no fields in indirect enum");
1243-
auto &field = rti->getFields()[0];
1244-
auto *type_ref = field.TR;
1245-
result = GetTypeFromTypeRef(*ts, type_ref);
1246-
child_byte_offset = field.Offset;
1247-
} else
1298+
else {
1299+
if (is_indirect_enum) {
1300+
auto type_or_err = get_from_indirect_enum();
1301+
// Only if this couldn't be resolved as an instance pointer, carry on.
1302+
if (!type_or_err || *type_or_err)
1303+
return type_or_err;
1304+
}
12481305
result = GetTypeFromTypeRef(*ts, field.TR);
1306+
}
1307+
12491308
// Bug-for-bug compatibility. See comment in
12501309
// SwiftASTContext::GetBitSize().
12511310
if (result.IsFunctionType())
@@ -1395,6 +1454,10 @@ llvm::Expected<CompilerType> SwiftLanguageRuntime::GetChildCompilerTypeAtIndex(
13951454
if (!reflection_ctx)
13961455
return llvm::createStringError("no reflection context");
13971456

1457+
// Indirect enums.
1458+
if (type.GetTypeInfo() & lldb::eTypeIsEnumeration)
1459+
return get_from_indirect_enum();
1460+
13981461
CompilerType instance_type = valobj->GetCompilerType();
13991462
auto instance_ts =
14001463
instance_type.GetTypeSystem().dyn_cast_or_null<TypeSystemSwift>();
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
SWIFT_SOURCES := main.swift
2+
3+
include Makefile.rules
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import lldb
2+
from lldbsuite.test.lldbtest import *
3+
from lldbsuite.test.decorators import *
4+
import lldbsuite.test.lldbutil as lldbutil
5+
6+
class TestCase(TestBase):
7+
@swiftTest
8+
def test(self):
9+
"""Test indirect enums"""
10+
self.build()
11+
target, process, thread, bkpt = lldbutil.run_to_source_breakpoint(
12+
self, "break here", lldb.SBFileSpec("main.swift")
13+
)
14+
if self.TraceOn():
15+
self.expect('v')
16+
frame = thread.frames[0]
17+
generic_s = frame.FindVariable("generic_s")
18+
s = generic_s.GetChildMemberWithName("s")
19+
t = s.GetChildMemberWithName("t")
20+
lldbutil.check_variable(self, t, False, value="123")
21+
22+
generic_large_s = frame.FindVariable("generic_large_s")
23+
s = generic_s.GetChildMemberWithName("s")
24+
t = s.GetChildMemberWithName("t")
25+
lldbutil.check_variable(self, t, False, value="123")
26+
27+
generic_c = frame.FindVariable("generic_c")
28+
c = generic_c.GetChildMemberWithName("c")
29+
t = c.GetChildMemberWithName("t")
30+
lldbutil.check_variable(self, t, False, value="123")
31+
32+
multi_s = frame.FindVariable("multi_s")
33+
s = multi_s.GetChildMemberWithName("s")
34+
t = s.GetChildMemberWithName("t")
35+
lldbutil.check_variable(self, t, False, value="123")
36+
37+
multi_c = frame.FindVariable("multi_c")
38+
lldbutil.check_variable(self, multi_c, False, value="c")
39+
40+
tuple_a = frame.FindVariable("tuple_a")
41+
a = tuple_a.GetChildMemberWithName("a")
42+
self.assertEqual(a.GetNumChildren(), 2)
43+
lldbutil.check_variable(self, a.GetChildAtIndex(0), False, value="23")
44+
lldbutil.check_variable(self, a.GetChildAtIndex(1), False, summary='"hello"')
45+
tuple_b = frame.FindVariable("tuple_b")
46+
b = tuple_b.GetChildMemberWithName("b")
47+
self.assertEqual(b.GetNumChildren(), 1)
48+
lldbutil.check_variable(self, b.GetChildAtIndex(0), False, value="42")
49+
tuple_c = frame.FindVariable("tuple_c")
50+
c = tuple_c.GetChildMemberWithName("c")
51+
lldbutil.check_variable(self, c, False, value="32")
52+
tuple_d = frame.FindVariable("tuple_d")
53+
lldbutil.check_variable(self, tuple_d, False, value="d")
54+
55+
tree = frame.FindVariable("tree")
56+
n0 = tree.GetChildMemberWithName("node")
57+
n1 = n0.GetChildAtIndex(0)
58+
n2 = n1.GetChildAtIndex(0)
59+
l0 = n2.GetChildAtIndex(0)
60+
lldbutil.check_variable(self, l0.GetChildAtIndex(0), False, value="1")
61+
l1 = n2.GetChildAtIndex(1)
62+
lldbutil.check_variable(self, l1.GetChildAtIndex(0), False, value="2")
63+
l2 = n0.GetChildAtIndex(1)
64+
lldbutil.check_variable(self, l2.GetChildAtIndex(0), False, value="3")
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
struct S<T> {
2+
let t: T
3+
}
4+
5+
enum EGenericS<T> {
6+
indirect case s(S<T>)
7+
}
8+
9+
class C<T> {
10+
init(t: T) { self.t = t }
11+
let t: T
12+
}
13+
14+
struct LargeS<T> {
15+
let t: T
16+
let space = (0, 1, 2, 3, 4, 5, 6, 7)
17+
}
18+
19+
enum EGenericLargeS<T> {
20+
indirect case s(LargeS<T>)
21+
}
22+
23+
enum EGenericC<T> {
24+
indirect case c(C<T>)
25+
}
26+
27+
enum EGenericMulti<T> {
28+
indirect case s(S<T>)
29+
indirect case c(C<T>)
30+
}
31+
32+
enum ETuple {
33+
indirect case a(Int, String)
34+
indirect case b(Int)
35+
case c(Int)
36+
case d
37+
}
38+
39+
enum ETree<T> {
40+
indirect case node(ETree<T>, ETree<T>)
41+
case leaf(T)
42+
}
43+
44+
func main() {
45+
let generic_s = EGenericS<Int>.s(S(t: 123))
46+
let generic_large_s = EGenericLargeS<Int>.s(LargeS(t: 123))
47+
let generic_c = EGenericC<Int>.c(C(t: 123))
48+
let multi_s = EGenericMulti<Int>.s(S(t: 123))
49+
let multi_c = EGenericMulti<Int>.c(C(t: 123))
50+
let tuple_a = ETuple.a(23, "hello")
51+
let tuple_b = ETuple.b(42)
52+
let tuple_c = ETuple.c(32)
53+
let tuple_d = ETuple.d
54+
let tree = ETree<Int>.node(
55+
ETree<Int>.node(ETree<Int>.leaf(1),
56+
ETree<Int>.leaf(2)),
57+
ETree<Int>.leaf(3))
58+
print("break here")
59+
}
60+
61+
main()

0 commit comments

Comments
 (0)