Skip to content

Commit d7ebeac

Browse files
committed
Reimplement indirect enum handling on top of Reflection (NFC)
1 parent 148483b commit d7ebeac

File tree

8 files changed

+100
-94
lines changed

8 files changed

+100
-94
lines changed

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,12 @@ class TargetReflectionContext
127127
return type_info;
128128
}
129129

130+
const swift::reflection::TypeInfo *
131+
GetTypeInfoFromInstance(lldb::addr_t instance,
132+
swift::remote::TypeInfoProvider *provider) override {
133+
return m_reflection_ctx.getInstanceTypeInfo(instance, provider);
134+
}
135+
130136
swift::reflection::MemoryReader &GetReader() override {
131137
return m_reflection_ctx.getReader();
132138
}
@@ -169,6 +175,17 @@ class TargetReflectionContext
169175
return false;
170176
}
171177

178+
llvm::Optional<int32_t>
179+
ProjectEnumValue(swift::remote::RemoteAddress enum_addr,
180+
const swift::reflection::TypeRef *enum_type_ref,
181+
swift::remote::TypeInfoProvider *provider) override {
182+
int32_t case_idx;
183+
if (m_reflection_ctx.projectEnumValue(enum_addr, enum_type_ref, &case_idx,
184+
provider))
185+
return case_idx;
186+
return {};
187+
}
188+
172189
llvm::Optional<std::pair<const swift::reflection::TypeRef *,
173190
swift::reflection::RemoteAddress>>
174191
ProjectExistentialAndUnwrapClass(

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

Lines changed: 53 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -910,9 +910,12 @@ CompilerType SwiftLanguageRuntimeImpl::GetChildCompilerTypeAtIndex(
910910
if (!ts)
911911
return {};
912912

913+
lldb::addr_t pointer = LLDB_INVALID_ADDRESS;
913914
ExecutionContext exe_ctx;
914-
if (valobj)
915+
if (valobj) {
915916
exe_ctx = valobj->GetExecutionContextRef();
917+
pointer = valobj->GetPointerValue();
918+
}
916919

917920
// Deal with the LLDB-only SILPackType variant.
918921
if (auto pack_element_type = ts->GetSILPackElementAtIndex(type, idx)) {
@@ -935,6 +938,12 @@ CompilerType SwiftLanguageRuntimeImpl::GetChildCompilerTypeAtIndex(
935938
[&](const swift::reflection::FieldInfo &field,
936939
llvm::Optional<TypeSystemSwift::TupleElement> tuple,
937940
bool hide_existentials) -> CompilerType {
941+
bool is_indirect_enum =
942+
!field.Offset && field.TR &&
943+
llvm::isa<swift::reflection::BuiltinTypeRef>(field.TR) &&
944+
llvm::isa<swift::reflection::ReferenceTypeInfo>(field.TI) &&
945+
llvm::cast<swift::reflection::ReferenceTypeInfo>(field.TI)
946+
.getReferenceKind() == swift::reflection::ReferenceKind::Strong;
938947
child_name = tuple ? tuple->element_name.GetStringRef().str() : field.Name;
939948
child_byte_size = field.TI.getSize();
940949
child_byte_offset = field.Offset;
@@ -943,13 +952,36 @@ CompilerType SwiftLanguageRuntimeImpl::GetChildCompilerTypeAtIndex(
943952
child_is_base_class = false;
944953
child_is_deref_of_parent = false;
945954
language_flags = 0;
955+
if (is_indirect_enum)
956+
language_flags |= TypeSystemSwift::LanguageFlags::eIsIndirectEnumCase;
946957
// SwiftASTContext hardcodes the members of protocols as raw
947958
// pointers. Remote Mirrors reports them as UnknownObject instead.
948959
if (hide_existentials && ts->IsExistentialType(type.GetOpaqueQualType()))
949960
return ts->GetRawPointerType();
950-
CompilerType result =
951-
tuple ? tuple->element_type : GetTypeFromTypeRef(*ts, field.TR);
952-
// Bug-for-bug compatibility. See comment in SwiftASTContext::GetBitSize().
961+
CompilerType result;
962+
if (tuple)
963+
result = tuple->element_type;
964+
else if (is_indirect_enum) {
965+
ThreadSafeReflectionContext reflection_ctx = GetReflectionContext();
966+
if (!reflection_ctx)
967+
return {};
968+
// The indirect enum field should point to a closure context.
969+
LLDBTypeInfoProvider tip(*this, *ts);
970+
lldb::addr_t instance = MaskMaybeBridgedPointer(m_process, pointer);
971+
auto *ti = reflection_ctx->GetTypeInfoFromInstance(instance, &tip);
972+
if (!ti)
973+
return {};
974+
auto *rti = llvm::dyn_cast_or_null<swift::reflection::RecordTypeInfo>(ti);
975+
if (rti->getFields().size() < 1)
976+
return {};
977+
auto &field = rti->getFields()[0];
978+
auto *type_ref = field.TR;
979+
result = GetTypeFromTypeRef(*ts, type_ref);
980+
child_byte_offset = field.Offset;
981+
} else
982+
result = GetTypeFromTypeRef(*ts, field.TR);
983+
// Bug-for-bug compatibility. See comment in
984+
// SwiftASTContext::GetBitSize().
953985
if (result.IsFunctionType())
954986
child_byte_size = ts->GetPointerByteSize();
955987
return result;
@@ -1001,7 +1033,7 @@ CompilerType SwiftLanguageRuntimeImpl::GetChildCompilerTypeAtIndex(
10011033
child_is_base_class = false;
10021034
child_is_deref_of_parent = false;
10031035
language_flags = 0;
1004-
return ts->GetRawPointerType();
1036+
return ts->GetRawPointerType();
10051037
}
10061038
}
10071039
return get_from_field_info(fields[idx], tuple, true);
@@ -1013,20 +1045,8 @@ CompilerType SwiftLanguageRuntimeImpl::GetChildCompilerTypeAtIndex(
10131045
// Skip non-payload cases.
10141046
if (!enum_case.TR)
10151047
continue;
1016-
if (i++ == idx) {
1017-
auto is_indirect = [](const swift::reflection::FieldInfo &field) {
1018-
// FIXME: This is by observation. What's the correct condition?
1019-
if (auto *tr =
1020-
llvm::dyn_cast_or_null<swift::reflection::BuiltinTypeRef>(
1021-
field.TR))
1022-
return llvm::StringRef(tr->getMangledName()).equals("Bo");
1023-
return false;
1024-
};
1025-
auto result = get_from_field_info(enum_case, {}, true);
1026-
if (is_indirect(enum_case))
1027-
language_flags |= TypeSystemSwift::LanguageFlags::eIsIndirectEnumCase;
1028-
return result;
1029-
}
1048+
if (i++ == idx)
1049+
return get_from_field_info(enum_case, {}, true);
10301050
}
10311051
LLDB_LOGF(GetLog(LLDBLog::Types), "index %zu is out of bounds (%d)", idx,
10321052
eti->getNumPayloadCases());
@@ -1055,10 +1075,9 @@ CompilerType SwiftLanguageRuntimeImpl::GetChildCompilerTypeAtIndex(
10551075
if (!instance_ts)
10561076
return {};
10571077

1058-
// LLDBTypeInfoProvider needs to kept alive until as long as supers gets accessed.
1078+
// LLDBTypeInfoProvider needs to be kept alive while supers gets accessed.
10591079
llvm::SmallVector<SuperClassType, 2> supers;
10601080
LLDBTypeInfoProvider tip(*this, *instance_ts);
1061-
lldb::addr_t pointer = valobj->GetPointerValue();
10621081
reflection_ctx->ForEachSuperClassType(
10631082
&tip, pointer, [&](SuperClassType sc) -> bool {
10641083
if (!found_start) {
@@ -1984,62 +2003,38 @@ bool SwiftLanguageRuntimeImpl::GetDynamicTypeAndAddress_IndirectEnumCase(
19842003
ValueObject &in_value, lldb::DynamicValueType use_dynamic,
19852004
TypeAndOrName &class_type_or_name, Address &address,
19862005
Value::ValueType &value_type) {
1987-
static ConstString g_offset("offset");
1988-
1989-
DataExtractor data;
19902006
Status error;
1991-
if (!(in_value.GetParent() && in_value.GetParent()->GetData(data, error) &&
1992-
error.Success()))
1993-
return false;
1994-
1995-
bool has_payload;
1996-
bool is_indirect;
1997-
CompilerType payload_type;
1998-
if (!SwiftASTContext::GetSelectedEnumCase(
1999-
in_value.GetParent()->GetCompilerType(), data, nullptr, &has_payload,
2000-
&payload_type, &is_indirect))
2001-
return false;
2007+
CompilerType child_type = in_value.GetCompilerType();
2008+
class_type_or_name.SetCompilerType(child_type);
20022009

2003-
if (has_payload && is_indirect && payload_type)
2004-
class_type_or_name.SetCompilerType(payload_type);
2005-
2006-
lldb::addr_t box_addr = in_value.GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
2010+
auto *enum_obj = in_value.GetParent();
2011+
lldb::addr_t box_addr = enum_obj->GetPointerValue();
20072012
if (box_addr == LLDB_INVALID_ADDRESS)
20082013
return false;
20092014

2010-
box_addr = MaskMaybeBridgedPointer(m_process, box_addr);
2015+
box_addr =
2016+
MaskMaybeBridgedPointer(m_process, box_addr);
20112017
lldb::addr_t box_location = m_process.ReadPointerFromMemory(box_addr, error);
20122018
if (box_location == LLDB_INVALID_ADDRESS)
20132019
return false;
2014-
2020+
20152021
box_location = MaskMaybeBridgedPointer(m_process, box_location);
2016-
ProcessStructReader reader(&m_process, box_location, GetBoxMetadataType());
2017-
uint32_t offset = reader.GetField<uint32_t>(g_offset);
2018-
lldb::addr_t box_value = box_addr + offset;
2019-
2020-
// try to read one byte at the box value
2021-
m_process.ReadUnsignedIntegerFromMemory(box_value, 1, 0, error);
2022-
if (error.Fail()) // and if that fails, then we're off in no man's land
2023-
return false;
2024-
2025-
Flags type_info(payload_type.GetTypeInfo());
2022+
lldb::addr_t box_value = box_addr + in_value.GetByteOffset();
2023+
Flags type_info(child_type.GetTypeInfo());
20262024
if (type_info.AllSet(eTypeIsSwift) &&
20272025
type_info.AnySet(eTypeIsClass | eTypeIsProtocol)) {
20282026
ExecutionContext exe_ctx = in_value.GetExecutionContextRef();
20292027
ValueObjectSP valobj_sp = ValueObjectMemory::Create(
2030-
exe_ctx.GetBestExecutionContextScope(), "_", box_value, payload_type);
2028+
exe_ctx.GetBestExecutionContextScope(), "_", box_value, child_type);
20312029
if (!valobj_sp)
20322030
return false;
20332031

2034-
if (!GetDynamicTypeAndAddress(*valobj_sp, use_dynamic, class_type_or_name,
2035-
address, value_type))
2036-
return false;
2037-
2038-
address.SetRawAddress(box_value);
2039-
return true;
2032+
return GetDynamicTypeAndAddress(*valobj_sp, use_dynamic, class_type_or_name,
2033+
address, value_type);
20402034
} else {
20412035
// This is most likely a statically known type.
20422036
address.SetLoadAddress(box_value, &m_process.GetTarget());
2037+
value_type = Value::GetValueTypeFromAddressType(eAddressTypeLoad);
20432038
return true;
20442039
}
20452040
}

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,9 @@ class SwiftLanguageRuntimeImpl {
243243
virtual const swift::reflection::TypeInfo *
244244
GetTypeInfo(const swift::reflection::TypeRef *type_ref,
245245
swift::remote::TypeInfoProvider *provider) = 0;
246+
virtual const swift::reflection::TypeInfo *
247+
GetTypeInfoFromInstance(lldb::addr_t instance,
248+
swift::remote::TypeInfoProvider *provider) = 0;
246249
virtual swift::remote::MemoryReader &GetReader() = 0;
247250
virtual const swift::reflection::TypeRef *
248251
LookupSuperclass(const swift::reflection::TypeRef *tr) = 0;
@@ -255,6 +258,10 @@ class SwiftLanguageRuntimeImpl {
255258
ProjectExistentialAndUnwrapClass(
256259
swift::remote::RemoteAddress existential_addess,
257260
const swift::reflection::TypeRef &existential_tr) = 0;
261+
virtual llvm::Optional<int32_t>
262+
ProjectEnumValue(swift::remote::RemoteAddress enum_addr,
263+
const swift::reflection::TypeRef *enum_type_ref,
264+
swift::remote::TypeInfoProvider *provider) = 0;
258265
virtual const swift::reflection::TypeRef *
259266
ReadTypeFromMetadata(lldb::addr_t metadata_address,
260267
bool skip_artificial_subclasses = false) = 0;

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5085,6 +5085,11 @@ bool SwiftASTContext::IsPossibleDynamicType(opaque_compiler_type_t type,
50855085
can_type->isAnyExistentialType())
50865086
return true;
50875087

5088+
if (!IsImportedType(type) &&
5089+
(swift::isa<swift::EnumType>(can_type) ||
5090+
swift::isa<swift::BoundGenericEnumType>(can_type)))
5091+
return true;
5092+
50885093
// Dynamic Self types are resolved inside DoArchetypeBindingForType(),
50895094
// right before the actual archetype binding.
50905095
if (can_type->hasDynamicSelfType())

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -801,7 +801,7 @@ class SwiftASTContext : public TypeSystemSwift {
801801
uint32_t GetNumPointeeChildren(lldb::opaque_compiler_type_t type);
802802

803803
bool IsImportedType(lldb::opaque_compiler_type_t type,
804-
CompilerType *original_type) override;
804+
CompilerType *original_type = nullptr) override;
805805

806806
CompilerType GetReferentType(lldb::opaque_compiler_type_t type) override;
807807
CompilerType GetStaticSelfType(lldb::opaque_compiler_type_t type) override;

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2223,9 +2223,10 @@ bool TypeSystemSwiftTypeRef::IsPossibleDynamicType(opaque_compiler_type_t type,
22232223
case Node::Kind::ProtocolListWithAnyObject:
22242224
case Node::Kind::ExistentialMetatype:
22252225
case Node::Kind::DynamicSelf:
2226+
case Node::Kind::Enum:
2227+
case Node::Kind::BoundGenericEnum:
22262228
return true;
2227-
case Node::Kind::BoundGenericStructure:
2228-
case Node::Kind::BoundGenericEnum: {
2229+
case Node::Kind::BoundGenericStructure: {
22292230
if (node->getNumChildren() < 2)
22302231
return false;
22312232
NodePointer type_list = node->getLastChild();
@@ -3112,7 +3113,7 @@ CompilerType TypeSystemSwiftTypeRef::GetChildCompilerTypeAtIndex(
31123113
assert(Equivalent(child_is_base_class, ast_child_is_base_class));
31133114
assert(Equivalent(child_is_deref_of_parent, ast_child_is_deref_of_parent));
31143115
// There are cases where only the runtime correctly detects an indirect enum.
3115-
ast_language_flags |= language_flags & LanguageFlags::eIsIndirectEnumCase;
3116+
ast_language_flags |= (language_flags & LanguageFlags::eIsIndirectEnumCase);
31163117
assert(Equivalent(language_flags, ast_language_flags));
31173118
});
31183119
#endif

lldb/test/API/lang/swift/foundation_value_types/indexpath/main.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ func main() {
1616
var short_path = IndexPath(indexes: [1,2])
1717
var very_short_path = IndexPath(indexes: [1])
1818
var empty_path = IndexPath()
19-
print("done!") //% self.expect("frame variable path", substrs=['5 indices'])
19+
print("done!") //% self.expect("frame variable path -d run", substrs=['5 indices'])
2020
//% self.expect("frame variable short_path", substrs=['2 indices'])
2121
//% self.expect("frame variable very_short_path", substrs=['1 index'])
2222
//% self.expect("frame variable empty_path", substrs=['0 indices'])

lldb/test/API/lang/swift/variables/indirect_enums/TestIndirectEnumVariables.py

Lines changed: 12 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,6 @@ def test_indirect_enum_variables(self):
3737

3838
def setUp(self):
3939
TestBase.setUp(self)
40-
self.main_source = "main.swift"
41-
self.main_source_spec = lldb.SBFileSpec(self.main_source)
4240

4341
def get_variable(self, name):
4442
x = self.frame().FindVariable(name)
@@ -56,13 +54,13 @@ def check_enum(
5654
child_summary=None,
5755
):
5856
if value:
59-
self.assertTrue(
60-
enum.GetValue() == value,
57+
self.assertEqual(
58+
enum.GetValue(), value,
6159
"%s.GetValue() == %s" % (enum.GetName(), value),
6260
)
6361
if summary:
64-
self.assertTrue(
65-
enum.GetSummary() == summary,
62+
self.assertEqual(
63+
enum.GetSummary(), summary,
6664
"%s.GetSummary() == %s" % (enum.GetName(), summary),
6765
)
6866

@@ -74,40 +72,23 @@ def check_enum(
7472
child.SetPreferSyntheticValue(True)
7573
self.assertTrue(child.IsValid(), "child at path %s valid" % (child_path))
7674
if child_value:
77-
self.assertTrue(
78-
child.GetValue() == child_value,
75+
self.assertEqual(
76+
child.GetValue(), child_value,
7977
"%s.GetValue() == %s" % (child.GetName(), child_value),
8078
)
8179
if child_summary:
82-
self.assertTrue(
83-
child.GetSummary() == child_summary,
80+
self.assertEqual(
81+
child.GetSummary(), child_summary,
8482
"%s.GetSummary() == %s" % (child.GetName(), child_summary),
8583
)
8684

8785
def do_test(self, break_pattern):
8886
"""Tests that indirect Enum variables display correctly"""
89-
exe_name = "a.out"
90-
exe = self.getBuildArtifact(exe_name)
91-
92-
# Create the target
93-
target = self.dbg.CreateTarget(exe)
94-
self.assertTrue(target, VALID_TARGET)
95-
96-
# Set the breakpoints
97-
breakpoint = target.BreakpointCreateBySourceRegex(
98-
break_pattern, self.main_source_spec
87+
target, process, thread, bkpt = lldbutil.run_to_source_breakpoint(
88+
self,
89+
break_pattern,
90+
lldb.SBFileSpec("main.swift"),
9991
)
100-
self.assertTrue(breakpoint.GetNumLocations() > 0, VALID_BREAKPOINT)
101-
102-
# Launch the process, and do not stop at the entry point.
103-
process = target.LaunchSimple(None, None, os.getcwd())
104-
105-
self.assertTrue(process, PROCESS_IS_VALID)
106-
107-
# Frame #0 should be at our breakpoint.
108-
threads = lldbutil.get_threads_stopped_at_breakpoint(process, breakpoint)
109-
110-
self.assertTrue(len(threads) == 1)
11192

11293
GP_StructType = self.get_variable("GP_StructType")
11394
GP_TupleType = self.get_variable("GP_TupleType")

0 commit comments

Comments
 (0)