Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@ struct DescriptorFinderForwarder : public swift::reflection::DescriptorFinder {
return nullptr;
}

std::unique_ptr<swift::reflection::MultiPayloadEnumDescriptorBase>
getMultiPayloadEnumDescriptor(const swift::reflection::TypeRef *TR) override {
if (m_descriptor_finder)
return m_descriptor_finder->getMultiPayloadEnumDescriptor(TR);
return nullptr;
}
void SetExternalDescriptorFinder(
swift::reflection::DescriptorFinder *desciptor_finder) {
m_descriptor_finder = desciptor_finder;
Expand Down
4 changes: 4 additions & 0 deletions lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserSwift.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,10 @@ class DWARFASTParserSwift : public lldb_private::plugin::dwarf::DWARFASTParser,
std::unique_ptr<swift::reflection::BuiltinTypeDescriptorBase>
getBuiltinTypeDescriptor(const swift::reflection::TypeRef *TR) override;

/// Returns a builtin descriptor constructed from DWARF info.
std::unique_ptr<swift::reflection::MultiPayloadEnumDescriptorBase>
getMultiPayloadEnumDescriptor(const swift::reflection::TypeRef *TR) override;

private:
/// Returns the canonical demangle tree of a die's type.
NodePointer GetCanonicalDemangleTree(DWARFDIE &die);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ getFieldDescriptorKindForDie(CompilerType type) {
return swift::reflection::FieldDescriptorKind::Class;
case lldb::eTypeClassStruct:
return swift::reflection::FieldDescriptorKind::Struct;
case lldb::eTypeClassEnumeration:
case lldb::eTypeClassUnion:
return swift::reflection::FieldDescriptorKind::Enum;
default:
LLDB_LOG(GetLog(LLDBLog::Types),
Expand Down Expand Up @@ -203,7 +203,12 @@ class DWARFFieldDescriptorImpl : public swift::reflection::FieldDescriptorBase {
std::vector<std::unique_ptr<swift::reflection::FieldRecordBase>>
getFieldRecordsFromEnum(const DWARFDIE &die,
plugin::dwarf::DWARFASTParser *dwarf_parser) {
std::vector<std::unique_ptr<swift::reflection::FieldRecordBase>> fields;
// Type lowering expects the payload fields to come before the non-payload
// ones.
std::vector<std::unique_ptr<swift::reflection::FieldRecordBase>>
payload_fields;
std::vector<std::unique_ptr<swift::reflection::FieldRecordBase>>
non_payload_fields;
auto variant_part = die.GetFirstChild();
for (DWARFDIE child_die : variant_part.children()) {
auto tag = child_die.Tag();
Expand All @@ -227,11 +232,69 @@ class DWARFFieldDescriptorImpl : public swift::reflection::FieldDescriptorBase {
bool is_indirect_case = false;
// Unused by type info construction.
bool is_var = false;
fields.emplace_back(std::make_unique<DWARFFieldRecordImpl>(
is_indirect_case, is_var, ConstString(member_field_name),
member_mangled_typename));

// If there is a type, this case has a payload.
if (member_type)
payload_fields.emplace_back(std::make_unique<DWARFFieldRecordImpl>(
is_indirect_case, is_var, ConstString(member_field_name),
member_mangled_typename));
else
non_payload_fields.emplace_back(std::make_unique<DWARFFieldRecordImpl>(
is_indirect_case, is_var, ConstString(member_field_name),
member_mangled_typename));
}
return fields;
// Add the non-payload cases to the end.
payload_fields.insert(payload_fields.end(),
std::make_move_iterator(non_payload_fields.begin()),
std::make_move_iterator(non_payload_fields.end()));
return payload_fields;
}
};

class DWARFMultiPayloadEnumDescriptorImpl
: public swift::reflection::MultiPayloadEnumDescriptorBase {
ConstString m_mangled_name;
DIERef m_die_ref;
std::vector<uint8_t> m_spare_bits_mask;
uint64_t m_byte_offset;

public:
~DWARFMultiPayloadEnumDescriptorImpl() override = default;

DWARFMultiPayloadEnumDescriptorImpl(ConstString mangled_name, DIERef die_ref,
std::vector<uint8_t> &&spare_bits_mask,
uint64_t byte_offset)
: swift::reflection::MultiPayloadEnumDescriptorBase(),
m_mangled_name(mangled_name), m_die_ref(die_ref),
m_spare_bits_mask(std::move(spare_bits_mask)),
m_byte_offset(byte_offset) {}

llvm::StringRef getMangledTypeName() override {
return m_mangled_name.GetStringRef();
}

uint32_t getContentsSizeInWords() const override {
return m_spare_bits_mask.size() / 4;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could benefit from a comment. Why 4; (is this dependent on ptrsize?) is this always divisible?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm using the same terminology as GenReflection for the function name here. A word in this case is 32 bits long so always divisible by 4.

}

size_t getSizeInBytes() const override { return m_spare_bits_mask.size(); }

uint32_t getFlags() const override { return usesPayloadSpareBits(); }

bool usesPayloadSpareBits() const override {
return !m_spare_bits_mask.empty();
}

uint32_t getPayloadSpareBitMaskByteOffset() const override {
return m_byte_offset;
}

uint32_t getPayloadSpareBitMaskByteCount() const override {
return getSizeInBytes();
}

const uint8_t *getPayloadSpareBits() const override {
return m_spare_bits_mask.data();
}
};
} // namespace
Expand Down Expand Up @@ -261,8 +324,8 @@ DWARFASTParserSwift::getBuiltinTypeDescriptor(
die.GetAttributeValueAsUnsigned(DW_AT_byte_size, LLDB_INVALID_ADDRESS);
if (byte_size == LLDB_INVALID_ADDRESS)
return {};
auto alignment = die.GetAttributeValueAsUnsigned(
DW_AT_alignment, byte_size == 0 ? 1 : byte_size);

auto alignment = die.GetAttributeValueAsUnsigned(DW_AT_alignment, 8);

// TODO: this seems simple to calculate but maybe we should encode the stride
// in DWARF? That's what reflection metadata does.
Expand All @@ -278,6 +341,97 @@ DWARFASTParserSwift::getBuiltinTypeDescriptor(
type.GetMangledTypeName());
}

std::unique_ptr<swift::reflection::MultiPayloadEnumDescriptorBase>
DWARFASTParserSwift::getMultiPayloadEnumDescriptor(
const swift::reflection::TypeRef *TR) {
if (!Target::GetGlobalProperties().GetSwiftEnableFullDwarfDebugging())
return nullptr;

auto pair = getTypeAndDie(m_swift_typesystem, TR);
if (!pair)
return nullptr;

auto [type, die] = *pair;
if (!die)
return nullptr;

auto kind = getFieldDescriptorKindForDie(type);
if (!kind)
return nullptr;

auto child_die = die.GetFirstChild();
auto bit_offset =
child_die.GetAttributeValueAsUnsigned(llvm::dwarf::DW_AT_bit_offset, 0);

auto byte_offset = (bit_offset + 7) / 8;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you use an llvm::align function from MatchExtras.h here?

const auto spare_bits_mask_die_it =
llvm::find_if(die.children(), [&](const DWARFDIE &child_die) {
return child_die.Tag() == llvm::dwarf::DW_TAG_APPLE_spare_bits_mask;
});

if (spare_bits_mask_die_it == child_die.children().end())

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think these error cases should probably all go to the dwarf log channel?

return nullptr;

auto spare_bits_mask_die = *spare_bits_mask_die_it;
DWARFAttributes attributes = spare_bits_mask_die.GetAttributes();
assert(attributes.Size() == 1 &&
"Unexpected attributes on spare bits mask die");
if (attributes.Size() != 1)
return nullptr;

dw_attr_t attribute = attributes.AttributeAtIndex(0);
assert(attribute == llvm::dwarf::DW_AT_const_value &&
"Unexpected attribute type on spare bits mask die");
if (attribute != llvm::dwarf::DW_AT_const_value)
return nullptr;

DWARFFormValue form_value;
attributes.ExtractFormValueAtIndex(0, form_value);

if (!form_value.IsValid()) {
if (auto *log = GetLog(LLDBLog::Types)) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dwarf instead of Types? Or maybe both?

std::stringstream ss;
TR->dump(ss);
LLDB_LOG(log,
"Could not produce MultiPayloadEnumTypeInfo for typeref: {0}",
ss.str());
}
return nullptr;
}
// If there's a block data, this is a number bigger than 64 bits already
// encoded as an array.
if (form_value.BlockData()) {
uint64_t block_length = form_value.Unsigned();
std::vector<uint8_t> bytes(form_value.BlockData(),
form_value.BlockData() + block_length);
return std::make_unique<DWARFMultiPayloadEnumDescriptorImpl>(
type.GetMangledTypeName(), *die.GetDIERef(),
std::move(bytes), byte_offset);
}

// If there is no block data, the spare bits mask is encoded as a single 64
// bit number. Convert this to a byte array with only the amount of bytes
// necessary to cover the whole number (see
// MultiPayloadEnumDescriptorBuilder::layout on GenReflection.cpp for a
// similar calculation when emitting this into metadata).
llvm::APInt bits(64, form_value.Unsigned());
auto bitsInMask = bits.getActiveBits();
uint32_t bytesInMask = (bitsInMask + 7) / 8;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use mathextras?

auto wordsInMask = (bytesInMask + 3) / 4;
bits = bits.zextOrTrunc(wordsInMask * 32);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this independent of ptrsize?


std::vector<uint8_t> bytes;
for (size_t i = 0; i < bytesInMask; ++i) {
uint8_t byte = bits.extractBitsAsZExtValue(8, 0);
bytes.push_back(byte);
bits.lshrInPlace(8);
}

return std::make_unique<DWARFMultiPayloadEnumDescriptorImpl>(
type.GetMangledTypeName(), *die.GetDIERef(), std::move(bytes),
byte_offset);
}

namespace {
DWARFDIE FindSuperClassDIE(DWARFDIE &die) {
const auto inheritance_die_it =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3434,6 +3434,9 @@ size_t TypeSystemSwiftTypeRef::GetIndexOfChildMemberWithName(
#ifndef NDEBUG
// This block is a custom VALIDATE_AND_RETURN implementation to support
// checking the return value, plus the by-ref `child_indexes`.
if (!ModuleList::GetGlobalModuleListProperties()
.GetSwiftValidateTypeSystem())
return index_size;
if (!GetSwiftASTContextFromExecutionContext(exe_ctx))
return index_size;
auto swift_scratch_ctx_lock = SwiftScratchContextLock(exe_ctx);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,102 @@ def test(self):
],
)

# TODO: test enums when "rdar://119343683 (Embedded Swift trivial case enum fails to link)" is solved
self.expect(
"frame variable nonPayload1", substrs=["NonPayloadEnum) nonPayload1 = one"]
)
self.expect(
"frame variable nonPayload2", substrs=["NonPayloadEnum) nonPayload2 = two"]
)
self.expect(
"frame variable singlePayload",
substrs=[
"SinglePayloadEnum) singlePayload = ",
"payload {",
"a = (field = 4.2000000000000002)",
"b = 123456",
],
)
self.expect(
"frame variable emptySinglePayload",
substrs=["SinglePayloadEnum) emptySinglePayload = nonPayloadTwo"],
)

self.expect("frame variable sup", substrs=["Sup) sup = ", "supField = 42"])
self.expect("frame variable sub", substrs=["Sub) sub = ", "Sup = {", "supField = 42", "subField = {", "a = (field = 4.2000000000000002", "b = 123456"])
self.expect("frame variable subSub", substrs=["SubSub) subSub =", "a.Sub = {", "a.Sup = {", "supField = 42", "subField = {", "a = (field = 4.2000000000000002", "b = 123456", "subSubField = (field = 4.2000000000000002)"])
self.expect(
"frame variable smallMultipayloadEnum1",
substrs=[
"SmallMultipayloadEnum) smallMultipayloadEnum1 = one {",
"one = two",
],
)
self.expect(
"frame variable smallMultipayloadEnum2",
substrs=[
"SmallMultipayloadEnum) smallMultipayloadEnum2 = two {",
"two = one",
],
)
self.expect(
"frame variable bigMultipayloadEnum1",
substrs=[
"BigMultipayloadEnum) bigMultipayloadEnum1 = one {",
"0 = ",
"(supField = 42)",
"1 = ",
"(supField = 43)",
"2 = ",
"(supField = 44)",
],
)

self.expect(
"frame variable fullMultipayloadEnum1",
substrs=["FullMultipayloadEnum) fullMultipayloadEnum1 = ", "(one = 120)"],
)
self.expect(
"frame variable fullMultipayloadEnum2",
substrs=[
"FullMultipayloadEnum) fullMultipayloadEnum2 = ",
"(two = 9.2100000000000008)",
],
)

self.expect(
"frame variable bigFullMultipayloadEnum1",
substrs=[
"a.BigFullMultipayloadEnum) bigFullMultipayloadEnum1 = one {",
"one = (0 = 209, 1 = 315)",
],
)
self.expect(
"frame variable bigFullMultipayloadEnum2",
substrs=[
"a.BigFullMultipayloadEnum) bigFullMultipayloadEnum2 = two {",
"two = (0 = 452.19999999999999, 1 = 753.89999999999998)",
],
)

self.expect("frame variable sup", substrs=["Sup) sup = ", "supField = 42"])
self.expect(
"frame variable sub",
substrs=[
"Sub) sub = ",
"Sup = {",
"supField = 42",
"subField = {",
"a = (field = 4.2000000000000002",
"b = 123456",
],
)
self.expect(
"frame variable subSub",
substrs=[
"SubSub) subSub =",
"a.Sub = {",
"a.Sup = {",
"supField = 42",
"subField = {",
"a = (field = 4.2000000000000002",
"b = 123456",
"subSubField = (field = 4.2000000000000002)",
],
)
Loading