Skip to content

Commit 67ed2ba

Browse files
Merge pull request #3889 from adrian-prantl/non-payload-enums
Eliminate unnecessary SwiftASTContext fallback in GetIndexOfChildMemb…
2 parents 0412b03 + 98a6c03 commit 67ed2ba

File tree

7 files changed

+87
-48
lines changed

7 files changed

+87
-48
lines changed

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ class SwiftLanguageRuntimeStub {
299299
return {};
300300
}
301301

302-
llvm::Optional<size_t> GetIndexOfChildMemberWithName(
302+
std::pair<bool, llvm::Optional<size_t>> GetIndexOfChildMemberWithName(
303303
CompilerType type, llvm::StringRef name, ExecutionContext *exe_ctx,
304304
bool omit_empty_base_classes, std::vector<uint32_t> &child_indexes) {
305305
STUB_LOG();
@@ -2209,7 +2209,8 @@ llvm::Optional<std::string> SwiftLanguageRuntime::GetEnumCaseName(
22092209
FORWARD(GetEnumCaseName, type, data, exe_ctx);
22102210
}
22112211

2212-
llvm::Optional<size_t> SwiftLanguageRuntime::GetIndexOfChildMemberWithName(
2212+
std::pair<bool, llvm::Optional<size_t>>
2213+
SwiftLanguageRuntime::GetIndexOfChildMemberWithName(
22132214
CompilerType type, llvm::StringRef name, ExecutionContext *exe_ctx,
22142215
bool omit_empty_base_classes, std::vector<uint32_t> &child_indexes) {
22152216
FORWARD(GetIndexOfChildMemberWithName, type, name, exe_ctx,

lldb/source/Plugins/LanguageRuntime/Swift/SwiftLanguageRuntime.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,17 @@ class SwiftLanguageRuntime : public LanguageRuntime {
280280
const DataExtractor &data,
281281
ExecutionContext *exe_ctx);
282282

283-
llvm::Optional<size_t> GetIndexOfChildMemberWithName(
283+
/// Behaves like the CompilerType::GetIndexOfChildMemberWithName()
284+
/// except for the more nuanced return value.
285+
///
286+
/// \returns {false, {}} on error.
287+
//
288+
/// \returns {true, {}} if the member exists, but it is an enum case
289+
/// without payload. Enum cases without payload
290+
/// don't have an index.
291+
///
292+
/// \returns {true, {num_idexes}} on success.
293+
std::pair<bool, llvm::Optional<size_t>> GetIndexOfChildMemberWithName(
284294
CompilerType type, llvm::StringRef name, ExecutionContext *exe_ctx,
285295
bool omit_empty_base_classes, std::vector<uint32_t> &child_indexes);
286296

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

Lines changed: 31 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1073,26 +1073,32 @@ GetTypeFromTypeRef(TypeSystemSwiftTypeRef &ts,
10731073
return ts.RemangleAsType(dem, node);
10741074
}
10751075

1076-
static llvm::Optional<size_t>
1076+
static std::pair<bool, llvm::Optional<size_t>>
10771077
findFieldWithName(const std::vector<swift::reflection::FieldInfo> &fields,
1078-
llvm::StringRef name, std::vector<uint32_t> &child_indexes,
1079-
uint32_t offset = 0) {
1078+
llvm::StringRef name, bool is_enum,
1079+
std::vector<uint32_t> &child_indexes, uint32_t offset = 0) {
10801080
uint32_t index = 0;
1081+
bool is_nonpayload_enum_case = false;
10811082
auto it = std::find_if(fields.begin(), fields.end(), [&](const auto &field) {
1082-
// A nonnull TypeRef is required for enum cases, where it represents cases
1083-
// that have a payload. In other types it will be true anyway.
1084-
if (field.TR == nullptr)
1085-
return false;
10861083
if (name != field.Name) {
1087-
++index;
1084+
// A nonnull TypeRef is required for enum cases, where it represents cases
1085+
// that have a payload. In other types it will be true anyway.
1086+
if (field.TR)
1087+
++index;
10881088
return false;
10891089
}
1090+
if (is_enum)
1091+
is_nonpayload_enum_case = (field.TR == nullptr);
10901092
return true;
10911093
});
1094+
// Not found.
10921095
if (it == fields.end())
1093-
return {};
1096+
return {false, {}};
1097+
// Found, but no index to report.
1098+
if (is_nonpayload_enum_case)
1099+
return {true, {}};
10941100
child_indexes.push_back(offset + index);
1095-
return child_indexes.size();
1101+
return {true, child_indexes.size()};
10961102
}
10971103

10981104
static llvm::Optional<std::string>
@@ -1136,21 +1142,22 @@ llvm::Optional<std::string> SwiftLanguageRuntimeImpl::GetEnumCaseName(
11361142
return {};
11371143
}
11381144

1139-
llvm::Optional<size_t> SwiftLanguageRuntimeImpl::GetIndexOfChildMemberWithName(
1145+
std::pair<bool, llvm::Optional<size_t>>
1146+
SwiftLanguageRuntimeImpl::GetIndexOfChildMemberWithName(
11401147
CompilerType type, llvm::StringRef name, ExecutionContext *exe_ctx,
11411148
bool omit_empty_base_classes, std::vector<uint32_t> &child_indexes) {
11421149
LLDB_SCOPED_TIMER();
11431150
auto *ts =
11441151
llvm::dyn_cast_or_null<TypeSystemSwiftTypeRef>(type.GetTypeSystem());
11451152
if (!ts)
1146-
return {};
1153+
return {false, {}};
11471154

11481155
using namespace swift::reflection;
11491156
// Try the static type metadata.
11501157
const TypeRef *tr = nullptr;
11511158
auto *ti = GetSwiftRuntimeTypeInfo(type, exe_ctx->GetFramePtr(), &tr);
11521159
if (!ti)
1153-
return {};
1160+
return {false, {}};
11541161
switch (ti->getKind()) {
11551162
case TypeInfoKind::Record: {
11561163
// Structs and Tuples.
@@ -1160,7 +1167,7 @@ llvm::Optional<size_t> SwiftLanguageRuntimeImpl::GetIndexOfChildMemberWithName(
11601167
case RecordKind::ThickFunction:
11611168
// There are two fields, `function` and `context`, but they're not exposed
11621169
// by lldb.
1163-
return 0;
1170+
return {true, {0}};
11641171
case RecordKind::OpaqueExistential:
11651172
// `OpaqueExistential` is documented as:
11661173
// An existential is a three-word buffer followed by value metadata...
@@ -1170,17 +1177,17 @@ llvm::Optional<size_t> SwiftLanguageRuntimeImpl::GetIndexOfChildMemberWithName(
11701177
uint32_t index;
11711178
if (name.take_back().getAsInteger(10, index) && index < 3) {
11721179
child_indexes.push_back(index);
1173-
return child_indexes.size();
1180+
return {true, child_indexes.size()};
11741181
}
11751182
}
1176-
return findFieldWithName(rti->getFields(), name, child_indexes, 3);
1183+
return findFieldWithName(rti->getFields(), name, false, child_indexes, 3);
11771184
default:
1178-
return findFieldWithName(rti->getFields(), name, child_indexes);
1185+
return findFieldWithName(rti->getFields(), name, false, child_indexes);
11791186
}
11801187
}
11811188
case TypeInfoKind::Enum: {
11821189
auto *eti = llvm::cast<EnumTypeInfo>(ti);
1183-
return findFieldWithName(eti->getCases(), name, child_indexes);
1190+
return findFieldWithName(eti->getCases(), name, true, child_indexes);
11841191
}
11851192
case TypeInfoKind::Reference: {
11861193
// Objects.
@@ -1207,20 +1214,21 @@ llvm::Optional<size_t> SwiftLanguageRuntimeImpl::GetIndexOfChildMemberWithName(
12071214
break;
12081215
auto *super_tr = builder.lookupSuperclass(current_tr);
12091216
uint32_t offset = super_tr ? 1 : 0;
1210-
if (auto size = findFieldWithName(record_ti->getFields(), name,
1211-
child_indexes, offset))
1212-
return size;
1217+
auto found_size = findFieldWithName(record_ti->getFields(), name, false,
1218+
child_indexes, offset);
1219+
if (found_size.first)
1220+
return found_size;
12131221
current_tr = super_tr;
12141222
child_indexes.push_back(0);
12151223
}
12161224
child_indexes.clear();
1217-
return {};
1225+
return {false, {}};
12181226
}
12191227
}
12201228
}
12211229
default:
12221230
// FIXME: Implement more cases.
1223-
return {};
1231+
return {false, {}};
12241232
}
12251233
}
12261234

lldb/source/Plugins/LanguageRuntime/Swift/SwiftLanguageRuntimeImpl.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ class SwiftLanguageRuntimeImpl {
131131
const DataExtractor &data,
132132
ExecutionContext *exe_ctx);
133133

134-
llvm::Optional<size_t> GetIndexOfChildMemberWithName(
134+
std::pair<bool, llvm::Optional<size_t>> GetIndexOfChildMemberWithName(
135135
CompilerType type, llvm::StringRef name, ExecutionContext *exe_ctx,
136136
bool omit_empty_base_classes, std::vector<uint32_t> &child_indexes);
137137

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

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2802,27 +2802,29 @@ size_t TypeSystemSwiftTypeRef::GetIndexOfChildMemberWithName(
28022802
child_indexes));
28032803
if (auto *exe_scope = exe_ctx->GetBestExecutionContextScope())
28042804
if (auto *runtime =
2805-
SwiftLanguageRuntime::Get(exe_scope->CalculateProcess()))
2806-
if (auto index_size = runtime->GetIndexOfChildMemberWithName(
2807-
GetCanonicalType(type), name, exe_ctx, omit_empty_base_classes,
2808-
child_indexes)) {
2805+
SwiftLanguageRuntime::Get(exe_scope->CalculateProcess())) {
2806+
auto found_numidx = runtime->GetIndexOfChildMemberWithName(
2807+
GetCanonicalType(type), name, exe_ctx, omit_empty_base_classes,
2808+
child_indexes);
2809+
if (found_numidx.first) {
2810+
size_t index_size = found_numidx.second.getValueOr(0);
28092811
#ifndef NDEBUG
28102812
// This block is a custom VALIDATE_AND_RETURN implementation to support
28112813
// checking the return value, plus the by-ref `child_indexes`.
28122814
if (!GetSwiftASTContext())
2813-
return *index_size;
2815+
return index_size;
28142816
auto ast_type = ReconstructType(type);
28152817
if (!ast_type)
2816-
return *index_size;
2818+
return index_size;
28172819
std::vector<uint32_t> ast_child_indexes;
28182820
auto ast_index_size =
28192821
GetSwiftASTContext()->GetIndexOfChildMemberWithName(
28202822
ast_type, name, exe_ctx, omit_empty_base_classes,
28212823
ast_child_indexes);
28222824
// The runtime has more info than the AST. No useful validation can be
28232825
// done.
2824-
if (*index_size > ast_index_size)
2825-
return *index_size;
2826+
if (index_size > ast_index_size)
2827+
return index_size;
28262828

28272829
auto fail = [&]() {
28282830
auto join = [](const auto &v) {
@@ -2841,17 +2843,20 @@ size_t TypeSystemSwiftTypeRef::GetIndexOfChildMemberWithName(
28412843
assert(false &&
28422844
"TypeSystemSwiftTypeRef diverges from SwiftASTContext");
28432845
};
2844-
if (*index_size != ast_index_size)
2846+
if (index_size != ast_index_size)
28452847
fail();
2846-
for (unsigned i = 0; i < *index_size; ++i)
2848+
for (unsigned i = 0; i < index_size; ++i)
28472849
if (child_indexes[i] < ast_child_indexes[i])
28482850
// When the runtime may know know about more children. When this
28492851
// happens, indexes will be larger. But if an index is smaller, that
28502852
// means the runtime has dropped info somehow.
28512853
fail();
28522854
#endif
2853-
return *index_size;
2855+
return index_size;
28542856
}
2857+
// If we're here, the runtime didn't find type info.
2858+
assert(!found_numidx.first);
2859+
}
28552860

28562861
LLDB_LOGF(GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES),
28572862
"Using SwiftASTContext::GetIndexOfChildMemberWithName fallback for "

lldb/test/Shell/Swift/Inputs/No.swiftmodule.swift

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,36 @@
11
import NoSwiftmoduleHelper
22

33
// The struct is resolved using type metadata and the Swift runtime.
4-
struct s { let i = 0 }
4+
struct S { let i = 0 }
55

66
func useTypeFromOtherModule(x: S2) {
77
// break here
88
}
99

10+
enum NoPayload {
11+
case first
12+
case second
13+
}
14+
15+
enum WithPayload {
16+
case empty
17+
case with(i: Int)
18+
}
19+
1020
func f<T>(_ t: T) {
11-
let number = 1 // CHECK-DAG: (Int) number = 1
12-
let array = [1, 2, 3] // CHECK-DAG: ([Int]) array = 3 values
13-
let string = "hello" // CHECK-DAG: (String) string = "hello"
14-
let tuple = (0, 1) // CHECK-DAG: (Int, Int) tuple = (0 = 0, 1 = 1)
15-
let strct = s() // CHECK-DAG: strct = (i = 0)
16-
let strct2 = S2() // CHECK-DAG: strct2 = {}{{$}}
17-
let generic = t // CHECK-DAG: (Int) generic = 23
18-
let generic_tuple = (t, t) // CHECK-DAG: generic_tuple = (0 = 23, 1 = 23)
19-
let word = 0._builtinWordValue // CHECK-DAG: word = 0
21+
let number = 1 // CHECK-DAG: (Int) number {{=}} 1
22+
let array = [1, 2, 3] // CHECK-DAG: ([Int]) array {{=}} 3 values
23+
let string = "hello" // CHECK-DAG: (String) string {{=}} "hello"
24+
let tuple = (0, 1) // CHECK-DAG: (Int, Int) tuple {{=}} (0 = 0, 1 = 1)
25+
let strct = S() // CHECK-DAG: strct {{=}} (i = 0)
26+
let strct2 = S2() // CHECK-DAG: strct2 {{=}} {}{{$}}
27+
let generic = t // CHECK-DAG: (Int) generic {{=}} 23
28+
let generic_tuple = (t, t) // CHECK-DAG: generic_tuple {{=}} (0 = 23, 1 = 23)
29+
let word = 0._builtinWordValue // CHECK-DAG: word {{=}} 0
30+
let enum1 = NoPayload.second // CHECK-DAG: enum1 {{=}}
31+
// FIXME: Fails in swift::reflection::NoPayloadEnumTypeInfo::projectEnumValue: .second
32+
let enum2 = WithPayload.with(i:42) // CHECK-DAG: enum2 {{=}} with
33+
// CHECK-DAG: i {{=}} 42
2034
print(number)
2135
useTypeFromOtherModule(x: S2())
2236
}

lldb/test/Shell/Swift/No.swiftmodule.test

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,4 @@ run
2727
fr var
2828
up
2929
fr var
30+
quit

0 commit comments

Comments
 (0)