Skip to content

Commit aeb25ee

Browse files
committed
Add SwiftLanguageRuntime support for implicit enum members.
To verify this I also added a new assertion that replaces the // FIXME unimplemented comments sprinkled over the code. This uncoverd a bunch mre bugs related to implicit fields that are also fixed in this patch. One issue with nested enums is described in a comment but not yet fixed.
1 parent 136fc48 commit aeb25ee

File tree

6 files changed

+138
-48
lines changed

6 files changed

+138
-48
lines changed

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

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -310,9 +310,11 @@ class SwiftLanguageRuntimeStub {
310310
return {};
311311
}
312312

313-
std::pair<bool, llvm::Optional<size_t>> GetIndexOfChildMemberWithName(
314-
CompilerType type, llvm::StringRef name, ExecutionContext *exe_ctx,
315-
bool omit_empty_base_classes, std::vector<uint32_t> &child_indexes) {
313+
std::pair<SwiftLanguageRuntime::LookupResult, llvm::Optional<size_t>>
314+
GetIndexOfChildMemberWithName(CompilerType type, llvm::StringRef name,
315+
ExecutionContext *exe_ctx,
316+
bool omit_empty_base_classes,
317+
std::vector<uint32_t> &child_indexes) {
316318
STUB_LOG();
317319
return {};
318320
}
@@ -2427,7 +2429,7 @@ llvm::Optional<std::string> SwiftLanguageRuntime::GetEnumCaseName(
24272429
FORWARD(GetEnumCaseName, type, data, exe_ctx);
24282430
}
24292431

2430-
std::pair<bool, llvm::Optional<size_t>>
2432+
std::pair<SwiftLanguageRuntime::LookupResult, llvm::Optional<size_t>>
24312433
SwiftLanguageRuntime::GetIndexOfChildMemberWithName(
24322434
CompilerType type, llvm::StringRef name, ExecutionContext *exe_ctx,
24332435
bool omit_empty_base_classes, std::vector<uint32_t> &child_indexes) {

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

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,17 @@ class SwiftLanguageRuntime : public LanguageRuntime {
323323
const DataExtractor &data,
324324
ExecutionContext *exe_ctx);
325325

326+
enum LookupResult {
327+
/// Failed due to missing reflection meatadata or unimplemented
328+
/// functionality. Should retry with SwiftASTContext.
329+
eError = 0,
330+
/// Success.
331+
eFound,
332+
/// Found complete type info, lookup unsuccessful.
333+
/// Do not waste time retrying.
334+
eNotFound
335+
};
336+
326337
/// Behaves like the CompilerType::GetIndexOfChildMemberWithName()
327338
/// except for the more nuanced return value.
328339
///
@@ -333,9 +344,11 @@ class SwiftLanguageRuntime : public LanguageRuntime {
333344
/// don't have an index.
334345
///
335346
/// \returns {true, {num_idexes}} on success.
336-
std::pair<bool, llvm::Optional<size_t>> GetIndexOfChildMemberWithName(
337-
CompilerType type, llvm::StringRef name, ExecutionContext *exe_ctx,
338-
bool omit_empty_base_classes, std::vector<uint32_t> &child_indexes);
347+
std::pair<LookupResult, llvm::Optional<size_t>>
348+
GetIndexOfChildMemberWithName(CompilerType type, llvm::StringRef name,
349+
ExecutionContext *exe_ctx,
350+
bool omit_empty_base_classes,
351+
std::vector<uint32_t> &child_indexes);
339352

340353
/// Ask Remote Mirrors about a child of a composite type.
341354
CompilerType GetChildCompilerTypeAtIndex(

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

Lines changed: 83 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -610,6 +610,20 @@ GetExistentialSyntheticChildren(std::shared_ptr<TypeSystemSwiftTypeRef> ts,
610610
assert(children.size());
611611
return children;
612612
}
613+
614+
/// Log the fact that a type kind is not supported.
615+
void LogUnimplementedTypeKind(const char *function, CompilerType type) {
616+
// When running the test suite assert that all cases are covered.
617+
LLDB_LOG(GetLog(LLDBLog::Types), "{0}: unimplemented type info in {1}",
618+
type.GetMangledTypeName(), function);
619+
#ifndef NDEBUG
620+
llvm::dbgs() << function << ": unimplemented type info in"
621+
<< type.GetMangledTypeName() << "\n";
622+
if (ModuleList::GetGlobalModuleListProperties().GetSwiftValidateTypeSystem())
623+
assert(false && "not implemented");
624+
#endif
625+
}
626+
613627
} // namespace
614628

615629
llvm::Optional<unsigned>
@@ -729,9 +743,7 @@ SwiftLanguageRuntimeImpl::GetNumChildren(CompilerType type,
729743
return {};
730744
}
731745

732-
// FIXME: Implement more cases.
733-
LLDB_LOG(GetLog(LLDBLog::Types), "{0}: unimplemented type info",
734-
type.GetMangledTypeName());
746+
LogUnimplementedTypeKind(__FUNCTION__, type);
735747
return {};
736748
}
737749

@@ -800,26 +812,34 @@ SwiftLanguageRuntimeImpl::GetNumFields(CompilerType type,
800812
}
801813
}
802814
default:
803-
// FIXME: Implement more cases.
815+
LogUnimplementedTypeKind(__FUNCTION__, type);
804816
return {};
805817
}
806818
}
807819

808-
static std::pair<bool, llvm::Optional<size_t>>
820+
static std::pair<SwiftLanguageRuntime::LookupResult, llvm::Optional<size_t>>
809821
findFieldWithName(const std::vector<swift::reflection::FieldInfo> &fields,
810822
const swift::reflection::TypeRef *tr, llvm::StringRef name,
811823
bool is_enum, std::vector<uint32_t> &child_indexes,
812824
uint32_t offset = 0) {
813825
uint32_t index = 0;
826+
uint32_t name_as_index = 0;
827+
bool name_is_index = false;
828+
auto *tuple_tr = llvm::dyn_cast<swift::reflection::TupleTypeRef>(tr);
829+
if (tuple_tr)
830+
name_is_index = !name.getAsInteger(10, name_as_index);
814831
bool is_nonpayload_enum_case = false;
832+
815833
auto it = std::find_if(fields.begin(), fields.end(), [&](const auto &field) {
834+
if (name_is_index && name_as_index == index)
835+
return true;
836+
816837
// In some situations the cached TI for a tuple type is missing the names,
817838
// but the type_ref has them.
818839
StringRef field_name = field.Name;
819840
if (!field.Name.size())
820-
if (auto *tuple_tr = llvm::dyn_cast<swift::reflection::TupleTypeRef>(tr))
821-
if (tuple_tr->getLabels().size() > index)
822-
field_name = tuple_tr->getLabels().at(index);
841+
if (tuple_tr && tuple_tr->getLabels().size() > index)
842+
field_name = tuple_tr->getLabels().at(index);
823843
if (name != field_name) {
824844
// A nonnull TypeRef is required for enum cases, where it represents cases
825845
// that have a payload. In other types it will be true anyway.
@@ -831,14 +851,15 @@ findFieldWithName(const std::vector<swift::reflection::FieldInfo> &fields,
831851
is_nonpayload_enum_case = (field.TR == nullptr);
832852
return true;
833853
});
854+
834855
// Not found.
835856
if (it == fields.end())
836-
return {false, {}};
857+
return {SwiftLanguageRuntime::eNotFound, {}};
837858
// Found, but no index to report.
838859
if (is_nonpayload_enum_case)
839-
return {true, {}};
860+
return {SwiftLanguageRuntime::eFound, {}};
840861
child_indexes.push_back(offset + index);
841-
return {true, child_indexes.size()};
862+
return {SwiftLanguageRuntime::eFound, child_indexes.size()};
842863
}
843864

844865
llvm::Optional<std::string> SwiftLanguageRuntimeImpl::GetEnumCaseName(
@@ -859,24 +880,30 @@ llvm::Optional<std::string> SwiftLanguageRuntimeImpl::GetEnumCaseName(
859880
if (eti->projectEnumValue(*GetMemoryReader(), addr, &case_index))
860881
return eti->getCases()[case_index].Name;
861882

883+
// FIXME: Enabling this fails TestSwiftNestedCEnums.py: The test
884+
// nests a C-style enum inside of a payload-carrying enum and most
885+
// likely we're not stripping off the outer enum's discriminator
886+
// before reading the value of the inner one.
887+
888+
// LogUnimplementedTypeKind(__FUNCTION__, type);
862889
return {};
863890
}
864891

865-
std::pair<bool, llvm::Optional<size_t>>
892+
std::pair<SwiftLanguageRuntime::LookupResult, llvm::Optional<size_t>>
866893
SwiftLanguageRuntimeImpl::GetIndexOfChildMemberWithName(
867894
CompilerType type, llvm::StringRef name, ExecutionContext *exe_ctx,
868895
bool omit_empty_base_classes, std::vector<uint32_t> &child_indexes) {
869896
LLDB_SCOPED_TIMER();
870897
auto ts = type.GetTypeSystem().dyn_cast_or_null<TypeSystemSwiftTypeRef>();
871898
if (!ts)
872-
return {false, {}};
899+
return {SwiftLanguageRuntime::eError, {}};
873900

874901
using namespace swift::reflection;
875902
// Try the static type metadata.
876903
const TypeRef *tr = nullptr;
877904
auto *ti = GetSwiftRuntimeTypeInfo(type, exe_ctx->GetFramePtr(), &tr);
878905
if (!ti)
879-
return {false, {}};
906+
return {SwiftLanguageRuntime::eError, {}};
880907
switch (ti->getKind()) {
881908
case TypeInfoKind::Record: {
882909
// Structs and Tuples.
@@ -886,7 +913,7 @@ SwiftLanguageRuntimeImpl::GetIndexOfChildMemberWithName(
886913
case RecordKind::ThickFunction:
887914
// There are two fields, `function` and `context`, but they're not exposed
888915
// by lldb.
889-
return {true, {0}};
916+
return {SwiftLanguageRuntime::eFound, {0}};
890917
case RecordKind::OpaqueExistential:
891918
// `OpaqueExistential` is documented as:
892919
// An existential is a three-word buffer followed by value metadata...
@@ -896,7 +923,7 @@ SwiftLanguageRuntimeImpl::GetIndexOfChildMemberWithName(
896923
uint32_t index;
897924
if (name.take_back().getAsInteger(10, index) && index < 3) {
898925
child_indexes.push_back(index);
899-
return {true, child_indexes.size()};
926+
return {SwiftLanguageRuntime::eFound, child_indexes.size()};
900927
}
901928
}
902929
return findFieldWithName(rti->getFields(), tr, name, false, child_indexes,
@@ -916,19 +943,23 @@ SwiftLanguageRuntimeImpl::GetIndexOfChildMemberWithName(
916943
case ReferenceKind::Weak:
917944
case ReferenceKind::Unowned:
918945
case ReferenceKind::Unmanaged:
946+
// Weak references are implicitly optional.
947+
child_indexes.push_back(0);
948+
if (name == "some")
949+
return {SwiftLanguageRuntime::eFound, child_indexes.size()};
919950
return GetIndexOfChildMemberWithName(GetWeakReferent(*ts, type), name,
920951
exe_ctx, omit_empty_base_classes,
921952
child_indexes);
922953
case ReferenceKind::Strong: {
923954
ThreadSafeReflectionContext reflection_ctx = GetReflectionContext();
924955
if (!reflection_ctx)
925-
return {false, {}};
956+
return {SwiftLanguageRuntime::eError, {}};
926957

927958
size_t idx = 0;
928959
for (auto &protocol_child : GetExistentialSyntheticChildren(ts, tr, ti)) {
929960
if (protocol_child.name == name) {
930961
child_indexes.push_back(idx);
931-
return {true, child_indexes.size()};
962+
return {SwiftLanguageRuntime::eFound, child_indexes.size()};
932963
}
933964
++idx;
934965
}
@@ -941,26 +972,46 @@ SwiftLanguageRuntimeImpl::GetIndexOfChildMemberWithName(
941972
auto *record_ti = llvm::dyn_cast_or_null<RecordTypeInfo>(
942973
reflection_ctx->GetClassInstanceTypeInfo(
943974
current_tr, &tip, ts->GetDescriptorFinder()));
944-
if (!record_ti)
945-
break;
975+
if (!record_ti) {
976+
child_indexes.clear();
977+
return {SwiftLanguageRuntime::eError, {}};
978+
}
946979
auto *super_tr = reflection_ctx->LookupSuperclass(
947980
current_tr, ts->GetDescriptorFinder());
948981
uint32_t offset = super_tr ? 1 : 0;
949982
auto found_size = findFieldWithName(record_ti->getFields(), current_tr,
950983
name, false, child_indexes, offset);
951-
if (found_size.first)
984+
if (found_size.first == SwiftLanguageRuntime::eError ||
985+
found_size.first == SwiftLanguageRuntime::eFound)
952986
return found_size;
953987
current_tr = super_tr;
954988
child_indexes.push_back(0);
955989
}
956990
child_indexes.clear();
957-
return {false, {}};
991+
return {SwiftLanguageRuntime::eNotFound, {}};
958992
}
959993
}
960994
}
995+
case TypeInfoKind::Builtin: {
996+
// Clang enums have an artificial rawValue property.
997+
CompilerType clang_type;
998+
if (ts->IsImportedType(type.GetOpaqueQualType(), &clang_type)) {
999+
bool is_signed;
1000+
if (clang_type.IsEnumerationType(is_signed) && name == "rawValue") {
1001+
child_indexes.push_back(0);
1002+
return {SwiftLanguageRuntime::eFound, {1}};
1003+
}
1004+
}
1005+
// SIMD types have an artificial _value.
1006+
if (name == "_value" && TypeSystemSwiftTypeRef::IsSIMDType(type)) {
1007+
child_indexes.push_back(0);
1008+
return {SwiftLanguageRuntime::eFound, {1}};
1009+
}
1010+
return {SwiftLanguageRuntime::eNotFound, {0}};
1011+
}
9611012
default:
962-
// FIXME: Implement more cases.
963-
return {false, {}};
1013+
LogUnimplementedTypeKind(__FUNCTION__, type);
1014+
return {SwiftLanguageRuntime::eError, {}};
9641015
}
9651016
}
9661017

@@ -1267,8 +1318,14 @@ CompilerType SwiftLanguageRuntimeImpl::GetChildCompilerTypeAtIndex(
12671318
i - 1);
12681319
return {};
12691320
}
1270-
LLDB_LOG(GetLog(LLDBLog::Types), "Cannot retrieve type information for {0}",
1271-
type.GetTypeName());
1321+
if (llvm::dyn_cast_or_null<swift::reflection::BuiltinTypeInfo>(ti)) {
1322+
// Clang enums have an artificial rawValue property. We could
1323+
// consider handling them here, but
1324+
// TypeSystemSwiftTypeRef::GetChildCompilerTypeAtIndex can also
1325+
// handle them and without a Process.
1326+
return {};
1327+
}
1328+
LogUnimplementedTypeKind(__FUNCTION__, type);
12721329
return {};
12731330
}
12741331

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -136,9 +136,11 @@ class SwiftLanguageRuntimeImpl {
136136
const DataExtractor &data,
137137
ExecutionContext *exe_ctx);
138138

139-
std::pair<bool, llvm::Optional<size_t>> GetIndexOfChildMemberWithName(
140-
CompilerType type, llvm::StringRef name, ExecutionContext *exe_ctx,
141-
bool omit_empty_base_classes, std::vector<uint32_t> &child_indexes);
139+
std::pair<SwiftLanguageRuntime::LookupResult, llvm::Optional<size_t>>
140+
GetIndexOfChildMemberWithName(CompilerType type, llvm::StringRef name,
141+
ExecutionContext *exe_ctx,
142+
bool omit_empty_base_classes,
143+
std::vector<uint32_t> &child_indexes);
142144

143145
CompilerType GetChildCompilerTypeAtIndex(
144146
CompilerType type, size_t idx, bool transparent_pointers,

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

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3413,7 +3413,10 @@ size_t TypeSystemSwiftTypeRef::GetIndexOfChildMemberWithName(
34133413
auto found_numidx = runtime->GetIndexOfChildMemberWithName(
34143414
GetCanonicalType(type), name, exe_ctx, omit_empty_base_classes,
34153415
child_indexes);
3416-
if (found_numidx.first) {
3416+
// Only use the SwiftASTContext fallback if there was an
3417+
// error. If the runtime had complete type info and couldn't
3418+
// find a result, don't waste time retrying.
3419+
if (found_numidx.first != SwiftLanguageRuntime::eError) {
34173420
size_t index_size = found_numidx.second.value_or(0);
34183421
#ifndef NDEBUG
34193422
// This block is a custom VALIDATE_AND_RETURN implementation to support
@@ -3436,17 +3439,11 @@ size_t TypeSystemSwiftTypeRef::GetIndexOfChildMemberWithName(
34363439
return index_size;
34373440

34383441
auto fail = [&]() {
3439-
auto join = [](const auto &v) {
3440-
std::ostringstream buf;
3441-
buf << "{";
3442-
for (const auto &item : v)
3443-
buf << item << ",";
3444-
buf.seekp(-1, std::ios_base::end);
3445-
buf << "}";
3446-
return buf.str();
3447-
};
3448-
llvm::dbgs() << join(child_indexes)
3449-
<< " != " << join(ast_child_indexes) << "\n";
3442+
llvm::dbgs() << "{";
3443+
llvm::interleaveComma(child_indexes, llvm::dbgs());
3444+
llvm::dbgs() << "} != {";
3445+
llvm::interleaveComma(ast_child_indexes, llvm::dbgs());
3446+
llvm::dbgs() << "}\n";
34503447
llvm::dbgs() << "failing type was " << (const char *)type
34513448
<< ", member was " << name << "\n";
34523449
assert(false &&
@@ -4291,6 +4288,23 @@ TypeSystemSwiftTypeRef::GetTypeBitAlign(opaque_compiler_type_t type,
42914288
return {};
42924289
}
42934290

4291+
bool TypeSystemSwiftTypeRef::IsSIMDType(CompilerType type) {
4292+
using namespace swift::Demangle;
4293+
Demangler dem;
4294+
swift::Demangle::NodePointer global =
4295+
dem.demangleSymbol(type.GetMangledTypeName().GetStringRef());
4296+
using Kind = swift::Demangle::Node::Kind;
4297+
auto *simd_storage = swift_demangle::nodeAtPath(
4298+
global, {Kind::TypeMangling, Kind::Type, Kind::Structure});
4299+
if (!simd_storage || simd_storage->getNumChildren() != 2)
4300+
return false;
4301+
auto base_type = simd_storage->getFirstChild();
4302+
auto wrapper = simd_storage->getLastChild();
4303+
return wrapper && wrapper->getKind() == Kind::Identifier &&
4304+
wrapper->hasText() && wrapper->getText().starts_with("SIMD") &&
4305+
base_type && base_type->getKind() == Kind::Structure;
4306+
}
4307+
42944308
#ifndef NDEBUG
42954309
static bool IsSIMDNode(NodePointer node) {
42964310
// A SIMD vector is a clang typealias whose identifier starts with "simd_".

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,8 @@ class TypeSystemSwiftTypeRef : public TypeSystemSwift {
282282
void SetCachedType(ConstString mangled, const lldb::TypeSP &type_sp);
283283
bool IsImportedType(lldb::opaque_compiler_type_t type,
284284
CompilerType *original_type) override;
285+
/// Determine whether this is a builtin SIMD type.
286+
static bool IsSIMDType(CompilerType type);
285287
/// Like \p IsImportedType(), but even returns Clang types that are also Swift
286288
/// builtins (int <-> Swift.Int) as Clang types.
287289
CompilerType GetAsClangTypeOrNull(lldb::opaque_compiler_type_t type,

0 commit comments

Comments
 (0)