30 ListEntry() =
default;
31 ListEntry(
ValueObjectSP entry_sp) : m_entry_sp(std::move(entry_sp)) {}
38 return ListEntry(m_entry_sp->GetChildMemberWithName(
"__next_"));
44 return ListEntry(m_entry_sp->GetChildMemberWithName(
"__prev_"));
47 uint64_t value()
const {
50 return m_entry_sp->GetValueAsUnsigned(0);
53 bool null() {
return (value() == 0); }
55 explicit operator bool() {
return GetEntry() && !null(); }
61 bool operator==(
const ListEntry &rhs)
const {
return value() == rhs.value(); }
63 bool operator!=(
const ListEntry &rhs)
const {
return !(*
this == rhs); }
71 ListIterator() =
default;
72 ListIterator(ListEntry entry) : m_entry(std::move(entry)) {}
73 ListIterator(
ValueObjectSP entry) : m_entry(std::move(entry)) {}
74 ListIterator(
ValueObject *entry) : m_entry(entry) {}
80 return m_entry.GetEntry();
83 return m_entry.GetEntry();
91 return m_entry.GetEntry();
94 bool operator==(
const ListIterator &rhs)
const {
95 return (rhs.m_entry == m_entry);
99 void next() { m_entry = m_entry.next(); }
101 void prev() { m_entry = m_entry.prev(); }
122 static constexpr bool g_use_loop_detect =
true;
123 size_t m_loop_detected = 0;
125 ListEntry m_slow_runner;
126 ListEntry m_fast_runner;
128 size_t m_list_capping_size = 0;
130 std::map<size_t, ListIterator> m_iterators;
132 bool HasLoop(
size_t count);
136class ForwardListFrontEnd :
public AbstractListFrontEnd {
145class ListFrontEnd :
public AbstractListFrontEnd {
149 ~ListFrontEnd()
override =
default;
168 m_list_capping_size = 0;
169 m_slow_runner.SetEntry(
nullptr);
170 m_fast_runner.SetEntry(
nullptr);
173 if (m_backend.GetTargetSP())
174 m_list_capping_size =
175 m_backend.GetTargetSP()->GetMaximumNumberOfChildrenToDisplay();
176 if (m_list_capping_size == 0)
177 m_list_capping_size = 255;
190bool AbstractListFrontEnd::HasLoop(
size_t count) {
191 if (!g_use_loop_detect)
197 if (m_loop_detected == 0) {
200 m_slow_runner = ListEntry(m_head).next();
201 m_fast_runner = m_slow_runner.next();
209 const size_t steps_to_run = std::min(count, m_count);
210 while (m_loop_detected < steps_to_run && m_slow_runner && m_fast_runner &&
211 m_slow_runner != m_fast_runner) {
213 m_slow_runner = m_slow_runner.next();
214 m_fast_runner = m_fast_runner.next().next();
217 if (count <= m_loop_detected)
219 if (!m_slow_runner || !m_fast_runner)
221 return m_slow_runner == m_fast_runner;
225 size_t advance = idx;
226 ListIterator current(m_head);
228 auto cached_iterator = m_iterators.find(idx - 1);
229 if (cached_iterator != m_iterators.end()) {
230 current = cached_iterator->second;
235 m_iterators[idx] = current;
239ForwardListFrontEnd::ForwardListFrontEnd(
ValueObject &valobj)
240 : AbstractListFrontEnd(valobj) {
244llvm::Expected<uint32_t> ForwardListFrontEnd::CalculateNumChildren() {
248 ListEntry current(m_head);
250 while (current && m_count < m_list_capping_size) {
252 current = current.next();
257ValueObjectSP ForwardListFrontEnd::GetChildAtIndex(uint32_t idx) {
258 if (idx >= CalculateNumChildrenIgnoringErrors())
264 if (HasLoop(idx + 1))
271 current_sp = current_sp->GetChildAtIndex(1);
279 current_sp->GetData(data,
error);
283 return CreateValueObjectFromData(llvm::formatv(
"[{0}]", idx).str(), data,
284 m_backend.GetExecutionContextRef(),
289 AbstractListFrontEnd::Update();
293 if (err.
Fail() || !backend_addr)
296 ValueObjectSP impl_sp(m_backend.GetChildMemberWithName(
"__before_begin_"));
298 return ChildCacheState::eRefetch;
304 return ChildCacheState::eRefetch;
306 m_head = impl_sp->GetChildMemberWithName(
"__next_").get();
308 return ChildCacheState::eRefetch;
312 : AbstractListFrontEnd(*valobj_sp) {
317llvm::Expected<uint32_t> ListFrontEnd::CalculateNumChildren() {
320 if (!m_head || !m_tail || m_node_address == 0)
323 ValueObjectSP size_node_sp(m_backend.GetChildMemberWithName(
"__size_"));
325 size_node_sp = m_backend.GetChildMemberWithName(
329 return llvm::createStringError(
"Unexpected std::list layout: expected "
330 "old __compressed_pair layout.");
336 m_count = size_node_sp->GetValueAsUnsigned(
UINT32_MAX);
341 uint64_t next_val = m_head->GetValueAsUnsigned(0);
342 uint64_t prev_val = m_tail->GetValueAsUnsigned(0);
343 if (next_val == 0 || prev_val == 0)
345 if (next_val == m_node_address)
347 if (next_val == prev_val)
350 ListEntry current(m_head);
351 while (current.next() && current.next().value() != m_node_address) {
353 current = current.next();
354 if (size > m_list_capping_size)
357 return m_count = (size - 1);
364 if (idx >= CalculateNumChildrenIgnoringErrors())
367 if (!m_head || !m_tail || m_node_address == 0)
370 if (HasLoop(idx + 1))
377 current_sp = current_sp->GetChildAtIndex(1);
381 if (current_sp->GetName() == g_next) {
382 ProcessSP process_sp(current_sp->GetProcessSP());
387 lldb::addr_t addr = current_sp->GetParent()->GetPointerValue();
388 addr = addr + 2 * process_sp->GetAddressByteSize();
391 CreateValueObjectFromAddress(
"__value_", addr, exe_ctx, m_element_type);
400 current_sp->GetData(data,
error);
405 name.
Printf(
"[%" PRIu64
"]", (uint64_t)idx);
406 return CreateValueObjectFromData(name.
GetString(), data,
407 m_backend.GetExecutionContextRef(),
412 AbstractListFrontEnd::Update();
418 if (err.
Fail() || !backend_addr)
420 m_node_address = backend_addr->GetValueAsUnsigned(0);
423 ValueObjectSP impl_sp(m_backend.GetChildMemberWithName(
"__end_"));
426 m_head = impl_sp->GetChildMemberWithName(
"__next_").get();
427 m_tail = impl_sp->GetChildMemberWithName(
"__prev_").get();
433 return (valobj_sp ?
new ListFrontEnd(valobj_sp) :
nullptr);
439 return valobj_sp ?
new ForwardListFrontEnd(*valobj_sp) :
nullptr;
static llvm::raw_ostream & error(Stream &strm)
static std::optional< size_t > CalculateNumChildren(CompilerType container_elem_type, uint64_t num_elements, CompilerType element_type)
Calculates the number of elements stored in a container (with element type 'container_elem_type') as ...
Generic representation of a type in a programming language.
CompilerType GetTypeTemplateArgument(size_t idx, bool expand_pack=false) const
size_t GetNumTemplateArguments(bool expand_pack=false) const
Return the number of template arguments the type has.
CompilerType GetNonReferenceType() const
If this type is a reference to a type (L value or R value reference), return a new type with the refe...
bool IsReferenceType(CompilerType *pointee_type=nullptr, bool *is_rvalue=nullptr) const
A uniqued constant string class.
const char * GetCString() const
Get the string value as a C string.
"lldb/Target/ExecutionContext.h" A class that contains an execution context.
bool Fail() const
Test for error condition.
llvm::StringRef GetString() const
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
virtual lldb::ChildCacheState Update()=0
This function is assumed to always succeed and if it fails, the front-end should know to deal with it...
virtual bool MightHaveChildren()=0
virtual size_t GetIndexOfChildWithName(ConstString name)=0
#define LLDB_INVALID_ADDRESS
A class that represents a running process on the host machine.
bool operator!=(const Address &lhs, const Address &rhs)
ChildCacheState
Specifies if children need to be re-computed after a call to SyntheticChildrenFrontEnd::Update.
@ eRefetch
Children need to be recomputed dynamically.
std::shared_ptr< lldb_private::ValueObject > ValueObjectSP
std::shared_ptr< lldb_private::Process > ProcessSP
bool LLDB_API operator==(const SBAddress &lhs, const SBAddress &rhs)