ValueObjectSyntheticFilter.cpp revision 360784
1//===-- ValueObjectSyntheticFilter.cpp --------------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "lldb/Core/ValueObjectSyntheticFilter.h"
10
11#include "lldb/Core/Value.h"
12#include "lldb/Core/ValueObject.h"
13#include "lldb/DataFormatters/TypeSynthetic.h"
14#include "lldb/Target/ExecutionContext.h"
15#include "lldb/Utility/Log.h"
16#include "lldb/Utility/Logging.h"
17#include "lldb/Utility/SharingPtr.h"
18#include "lldb/Utility/Status.h"
19
20#include "llvm/ADT/STLExtras.h"
21
22namespace lldb_private {
23class Declaration;
24}
25
26using namespace lldb_private;
27
28class DummySyntheticFrontEnd : public SyntheticChildrenFrontEnd {
29public:
30  DummySyntheticFrontEnd(ValueObject &backend)
31      : SyntheticChildrenFrontEnd(backend) {}
32
33  size_t CalculateNumChildren() override { return m_backend.GetNumChildren(); }
34
35  lldb::ValueObjectSP GetChildAtIndex(size_t idx) override {
36    return m_backend.GetChildAtIndex(idx, true);
37  }
38
39  size_t GetIndexOfChildWithName(ConstString name) override {
40    return m_backend.GetIndexOfChildWithName(name);
41  }
42
43  bool MightHaveChildren() override { return true; }
44
45  bool Update() override { return false; }
46};
47
48ValueObjectSynthetic::ValueObjectSynthetic(ValueObject &parent,
49                                           lldb::SyntheticChildrenSP filter)
50    : ValueObject(parent), m_synth_sp(filter), m_children_byindex(),
51      m_name_toindex(), m_synthetic_children_cache(),
52      m_synthetic_children_count(UINT32_MAX),
53      m_parent_type_name(parent.GetTypeName()),
54      m_might_have_children(eLazyBoolCalculate),
55      m_provides_value(eLazyBoolCalculate) {
56  SetName(parent.GetName());
57  CopyValueData(m_parent);
58  CreateSynthFilter();
59}
60
61ValueObjectSynthetic::~ValueObjectSynthetic() = default;
62
63CompilerType ValueObjectSynthetic::GetCompilerTypeImpl() {
64  return m_parent->GetCompilerType();
65}
66
67ConstString ValueObjectSynthetic::GetTypeName() {
68  return m_parent->GetTypeName();
69}
70
71ConstString ValueObjectSynthetic::GetQualifiedTypeName() {
72  return m_parent->GetQualifiedTypeName();
73}
74
75ConstString ValueObjectSynthetic::GetDisplayTypeName() {
76  if (ConstString synth_name = m_synth_filter_up->GetSyntheticTypeName())
77    return synth_name;
78
79  return m_parent->GetDisplayTypeName();
80}
81
82size_t ValueObjectSynthetic::CalculateNumChildren(uint32_t max) {
83  Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_DATAFORMATTERS);
84
85  UpdateValueIfNeeded();
86  if (m_synthetic_children_count < UINT32_MAX)
87    return m_synthetic_children_count <= max ? m_synthetic_children_count : max;
88
89  if (max < UINT32_MAX) {
90    size_t num_children = m_synth_filter_up->CalculateNumChildren(max);
91    LLDB_LOGF(log,
92              "[ValueObjectSynthetic::CalculateNumChildren] for VO of name "
93              "%s and type %s, the filter returned %zu child values",
94              GetName().AsCString(), GetTypeName().AsCString(), num_children);
95    return num_children;
96  } else {
97    size_t num_children = (m_synthetic_children_count =
98                               m_synth_filter_up->CalculateNumChildren(max));
99    LLDB_LOGF(log,
100              "[ValueObjectSynthetic::CalculateNumChildren] for VO of name "
101              "%s and type %s, the filter returned %zu child values",
102              GetName().AsCString(), GetTypeName().AsCString(), num_children);
103    return num_children;
104  }
105}
106
107lldb::ValueObjectSP
108ValueObjectSynthetic::GetDynamicValue(lldb::DynamicValueType valueType) {
109  if (!m_parent)
110    return lldb::ValueObjectSP();
111  if (IsDynamic() && GetDynamicValueType() == valueType)
112    return GetSP();
113  return m_parent->GetDynamicValue(valueType);
114}
115
116bool ValueObjectSynthetic::MightHaveChildren() {
117  if (m_might_have_children == eLazyBoolCalculate)
118    m_might_have_children =
119        (m_synth_filter_up->MightHaveChildren() ? eLazyBoolYes : eLazyBoolNo);
120  return (m_might_have_children != eLazyBoolNo);
121}
122
123uint64_t ValueObjectSynthetic::GetByteSize() { return m_parent->GetByteSize(); }
124
125lldb::ValueType ValueObjectSynthetic::GetValueType() const {
126  return m_parent->GetValueType();
127}
128
129void ValueObjectSynthetic::CreateSynthFilter() {
130  ValueObject *valobj_for_frontend = m_parent;
131  if (m_synth_sp->WantsDereference())
132  {
133    CompilerType type = m_parent->GetCompilerType();
134    if (type.IsValid() && type.IsPointerOrReferenceType())
135    {
136      Status error;
137      lldb::ValueObjectSP deref_sp = m_parent->Dereference(error);
138      if (error.Success())
139        valobj_for_frontend = deref_sp.get();
140    }
141  }
142  m_synth_filter_up = (m_synth_sp->GetFrontEnd(*valobj_for_frontend));
143  if (!m_synth_filter_up)
144    m_synth_filter_up = std::make_unique<DummySyntheticFrontEnd>(*m_parent);
145}
146
147bool ValueObjectSynthetic::UpdateValue() {
148  Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_DATAFORMATTERS);
149
150  SetValueIsValid(false);
151  m_error.Clear();
152
153  if (!m_parent->UpdateValueIfNeeded(false)) {
154    // our parent could not update.. as we are meaningless without a parent,
155    // just stop
156    if (m_parent->GetError().Fail())
157      m_error = m_parent->GetError();
158    return false;
159  }
160
161  // regenerate the synthetic filter if our typename changes
162  // <rdar://problem/12424824>
163  ConstString new_parent_type_name = m_parent->GetTypeName();
164  if (new_parent_type_name != m_parent_type_name) {
165    LLDB_LOGF(log,
166              "[ValueObjectSynthetic::UpdateValue] name=%s, type changed "
167              "from %s to %s, recomputing synthetic filter",
168              GetName().AsCString(), m_parent_type_name.AsCString(),
169              new_parent_type_name.AsCString());
170    m_parent_type_name = new_parent_type_name;
171    CreateSynthFilter();
172  }
173
174  // let our backend do its update
175  if (!m_synth_filter_up->Update()) {
176    LLDB_LOGF(log,
177              "[ValueObjectSynthetic::UpdateValue] name=%s, synthetic "
178              "filter said caches are stale - clearing",
179              GetName().AsCString());
180    // filter said that cached values are stale
181    {
182      std::lock_guard<std::mutex> guard(m_child_mutex);
183      m_children_byindex.clear();
184      m_name_toindex.clear();
185    }
186    // usually, an object's value can change but this does not alter its
187    // children count for a synthetic VO that might indeed happen, so we need
188    // to tell the upper echelons that they need to come back to us asking for
189    // children
190    m_children_count_valid = false;
191    {
192      std::lock_guard<std::mutex> guard(m_child_mutex);
193      m_synthetic_children_cache.clear();
194    }
195    m_synthetic_children_count = UINT32_MAX;
196    m_might_have_children = eLazyBoolCalculate;
197  } else {
198    LLDB_LOGF(log,
199              "[ValueObjectSynthetic::UpdateValue] name=%s, synthetic "
200              "filter said caches are still valid",
201              GetName().AsCString());
202  }
203
204  m_provides_value = eLazyBoolCalculate;
205
206  lldb::ValueObjectSP synth_val(m_synth_filter_up->GetSyntheticValue());
207
208  if (synth_val && synth_val->CanProvideValue()) {
209    LLDB_LOGF(log,
210              "[ValueObjectSynthetic::UpdateValue] name=%s, synthetic "
211              "filter said it can provide a value",
212              GetName().AsCString());
213
214    m_provides_value = eLazyBoolYes;
215    CopyValueData(synth_val.get());
216  } else {
217    LLDB_LOGF(log,
218              "[ValueObjectSynthetic::UpdateValue] name=%s, synthetic "
219              "filter said it will not provide a value",
220              GetName().AsCString());
221
222    m_provides_value = eLazyBoolNo;
223    CopyValueData(m_parent);
224  }
225
226  SetValueIsValid(true);
227  return true;
228}
229
230lldb::ValueObjectSP ValueObjectSynthetic::GetChildAtIndex(size_t idx,
231                                                          bool can_create) {
232  Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_DATAFORMATTERS);
233
234  LLDB_LOGF(log,
235            "[ValueObjectSynthetic::GetChildAtIndex] name=%s, retrieving "
236            "child at index %zu",
237            GetName().AsCString(), idx);
238
239  UpdateValueIfNeeded();
240
241  ValueObject *valobj;
242  bool child_is_cached;
243  {
244    std::lock_guard<std::mutex> guard(m_child_mutex);
245    auto cached_child_it = m_children_byindex.find(idx);
246    child_is_cached = cached_child_it != m_children_byindex.end();
247    if (child_is_cached)
248      valobj = cached_child_it->second;
249  }
250
251  if (!child_is_cached) {
252    if (can_create && m_synth_filter_up != nullptr) {
253      LLDB_LOGF(log,
254                "[ValueObjectSynthetic::GetChildAtIndex] name=%s, child at "
255                "index %zu not cached and will be created",
256                GetName().AsCString(), idx);
257
258      lldb::ValueObjectSP synth_guy = m_synth_filter_up->GetChildAtIndex(idx);
259
260      LLDB_LOGF(
261          log,
262          "[ValueObjectSynthetic::GetChildAtIndex] name=%s, child at index "
263          "%zu created as %p (is "
264          "synthetic: %s)",
265          GetName().AsCString(), idx, static_cast<void *>(synth_guy.get()),
266          synth_guy.get()
267              ? (synth_guy->IsSyntheticChildrenGenerated() ? "yes" : "no")
268              : "no");
269
270      if (!synth_guy)
271        return synth_guy;
272
273      {
274        std::lock_guard<std::mutex> guard(m_child_mutex);
275        if (synth_guy->IsSyntheticChildrenGenerated())
276          m_synthetic_children_cache.push_back(synth_guy);
277        m_children_byindex[idx] = synth_guy.get();
278      }
279      synth_guy->SetPreferredDisplayLanguageIfNeeded(
280          GetPreferredDisplayLanguage());
281      return synth_guy;
282    } else {
283      LLDB_LOGF(log,
284                "[ValueObjectSynthetic::GetChildAtIndex] name=%s, child at "
285                "index %zu not cached and cannot "
286                "be created (can_create = %s, synth_filter = %p)",
287                GetName().AsCString(), idx, can_create ? "yes" : "no",
288                static_cast<void *>(m_synth_filter_up.get()));
289
290      return lldb::ValueObjectSP();
291    }
292  } else {
293    LLDB_LOGF(log,
294              "[ValueObjectSynthetic::GetChildAtIndex] name=%s, child at "
295              "index %zu cached as %p",
296              GetName().AsCString(), idx, static_cast<void *>(valobj));
297
298    return valobj->GetSP();
299  }
300}
301
302lldb::ValueObjectSP
303ValueObjectSynthetic::GetChildMemberWithName(ConstString name,
304                                             bool can_create) {
305  UpdateValueIfNeeded();
306
307  uint32_t index = GetIndexOfChildWithName(name);
308
309  if (index == UINT32_MAX)
310    return lldb::ValueObjectSP();
311
312  return GetChildAtIndex(index, can_create);
313}
314
315size_t ValueObjectSynthetic::GetIndexOfChildWithName(ConstString name) {
316  UpdateValueIfNeeded();
317
318  uint32_t found_index = UINT32_MAX;
319  bool did_find;
320  {
321    std::lock_guard<std::mutex> guard(m_child_mutex);
322    auto name_to_index = m_name_toindex.find(name.GetCString());
323    did_find = name_to_index != m_name_toindex.end();
324    if (did_find)
325      found_index = name_to_index->second;
326  }
327
328  if (!did_find && m_synth_filter_up != nullptr) {
329    uint32_t index = m_synth_filter_up->GetIndexOfChildWithName(name);
330    if (index == UINT32_MAX)
331      return index;
332    std::lock_guard<std::mutex> guard(m_child_mutex);
333    m_name_toindex[name.GetCString()] = index;
334    return index;
335  } else if (!did_find && m_synth_filter_up == nullptr)
336    return UINT32_MAX;
337  else /*if (iter != m_name_toindex.end())*/
338    return found_index;
339}
340
341bool ValueObjectSynthetic::IsInScope() { return m_parent->IsInScope(); }
342
343lldb::ValueObjectSP ValueObjectSynthetic::GetNonSyntheticValue() {
344  return m_parent->GetSP();
345}
346
347void ValueObjectSynthetic::CopyValueData(ValueObject *source) {
348  m_value = (source->UpdateValueIfNeeded(), source->GetValue());
349  ExecutionContext exe_ctx(GetExecutionContextRef());
350  m_error = m_value.GetValueAsData(&exe_ctx, m_data, GetModule().get());
351}
352
353bool ValueObjectSynthetic::CanProvideValue() {
354  if (!UpdateValueIfNeeded())
355    return false;
356  if (m_provides_value == eLazyBoolYes)
357    return true;
358  return m_parent->CanProvideValue();
359}
360
361bool ValueObjectSynthetic::SetValueFromCString(const char *value_str,
362                                               Status &error) {
363  return m_parent->SetValueFromCString(value_str, error);
364}
365
366void ValueObjectSynthetic::SetFormat(lldb::Format format) {
367  if (m_parent) {
368    m_parent->ClearUserVisibleData(eClearUserVisibleDataItemsAll);
369    m_parent->SetFormat(format);
370  }
371  this->ValueObject::SetFormat(format);
372  this->ClearUserVisibleData(eClearUserVisibleDataItemsAll);
373}
374
375void ValueObjectSynthetic::SetPreferredDisplayLanguage(
376    lldb::LanguageType lang) {
377  this->ValueObject::SetPreferredDisplayLanguage(lang);
378  if (m_parent)
379    m_parent->SetPreferredDisplayLanguage(lang);
380}
381
382lldb::LanguageType ValueObjectSynthetic::GetPreferredDisplayLanguage() {
383  if (m_preferred_display_language == lldb::eLanguageTypeUnknown) {
384    if (m_parent)
385      return m_parent->GetPreferredDisplayLanguage();
386    return lldb::eLanguageTypeUnknown;
387  } else
388    return m_preferred_display_language;
389}
390
391bool ValueObjectSynthetic::IsSyntheticChildrenGenerated() {
392  if (m_parent)
393    return m_parent->IsSyntheticChildrenGenerated();
394  return false;
395}
396
397void ValueObjectSynthetic::SetSyntheticChildrenGenerated(bool b) {
398  if (m_parent)
399    m_parent->SetSyntheticChildrenGenerated(b);
400  this->ValueObject::SetSyntheticChildrenGenerated(b);
401}
402
403bool ValueObjectSynthetic::GetDeclaration(Declaration &decl) {
404  if (m_parent)
405    return m_parent->GetDeclaration(decl);
406
407  return ValueObject::GetDeclaration(decl);
408}
409
410uint64_t ValueObjectSynthetic::GetLanguageFlags() {
411  if (m_parent)
412    return m_parent->GetLanguageFlags();
413  return this->ValueObject::GetLanguageFlags();
414}
415
416void ValueObjectSynthetic::SetLanguageFlags(uint64_t flags) {
417  if (m_parent)
418    m_parent->SetLanguageFlags(flags);
419  else
420    this->ValueObject::SetLanguageFlags(flags);
421}
422