11
11
#include " Plugins/TypeSystem/Clang/TypeSystemClang.h"
12
12
#include " lldb/Symbol/Function.h"
13
13
#include " lldb/Symbol/VariableList.h"
14
- #include " lldb/Utility/LLDBLog.h"
15
- #include " lldb/Utility/Log.h"
16
14
17
15
using namespace lldb ;
18
16
using namespace lldb_private ;
@@ -61,19 +59,23 @@ static Function *ExtractDestroyFunction(lldb::TargetSP target_sp,
61
59
return destroy_func_address.CalculateSymbolContextFunction ();
62
60
}
63
61
64
- static CompilerType InferPromiseType (Function &destroy_func) {
65
- Block &block = destroy_func.GetBlock (true );
62
+ // clang generates aritifical `__promise` and `__coro_frame` variables inside
63
+ // the destroy function. Look for those variables and extract their type.
64
+ static CompilerType InferArtificialCoroType (Function *destroy_func,
65
+ ConstString var_name) {
66
+ if (!destroy_func)
67
+ return {};
68
+
69
+ Block &block = destroy_func->GetBlock (true );
66
70
auto variable_list = block.GetBlockVariableList (true );
67
71
68
- // clang generates an artificial `__promise` variable inside the
69
- // `destroy` function. Look for it.
70
- auto promise_var = variable_list->FindVariable (ConstString (" __promise" ));
71
- if (!promise_var)
72
+ auto var = variable_list->FindVariable (var_name);
73
+ if (!var)
72
74
return {};
73
- if (!promise_var ->IsArtificial ())
75
+ if (!var ->IsArtificial ())
74
76
return {};
75
77
76
- Type *promise_type = promise_var ->GetType ();
78
+ Type *promise_type = var ->GetType ();
77
79
if (!promise_type)
78
80
return {};
79
81
return promise_type->GetForwardCompilerType ();
@@ -107,30 +109,17 @@ lldb_private::formatters::StdlibCoroutineHandleSyntheticFrontEnd::
107
109
108
110
llvm::Expected<uint32_t > lldb_private::formatters::
109
111
StdlibCoroutineHandleSyntheticFrontEnd::CalculateNumChildren () {
110
- if (!m_resume_ptr_sp || !m_destroy_ptr_sp)
111
- return 0 ;
112
-
113
- return m_promise_ptr_sp ? 3 : 2 ;
112
+ return m_children.size ();
114
113
}
115
114
116
115
lldb::ValueObjectSP lldb_private::formatters::
117
116
StdlibCoroutineHandleSyntheticFrontEnd::GetChildAtIndex (uint32_t idx) {
118
- switch (idx) {
119
- case 0 :
120
- return m_resume_ptr_sp;
121
- case 1 :
122
- return m_destroy_ptr_sp;
123
- case 2 :
124
- return m_promise_ptr_sp;
125
- }
126
- return lldb::ValueObjectSP ();
117
+ return idx < m_children.size () ? m_children[idx] : lldb::ValueObjectSP ();
127
118
}
128
119
129
120
lldb::ChildCacheState
130
121
lldb_private::formatters::StdlibCoroutineHandleSyntheticFrontEnd::Update () {
131
- m_resume_ptr_sp.reset ();
132
- m_destroy_ptr_sp.reset ();
133
- m_promise_ptr_sp.reset ();
122
+ m_children.clear ();
134
123
135
124
ValueObjectSP valobj_sp = m_backend.GetNonSyntheticValue ();
136
125
if (!valobj_sp)
@@ -140,77 +129,78 @@ lldb_private::formatters::StdlibCoroutineHandleSyntheticFrontEnd::Update() {
140
129
if (frame_ptr_addr == 0 || frame_ptr_addr == LLDB_INVALID_ADDRESS)
141
130
return lldb::ChildCacheState::eRefetch;
142
131
143
- auto ast_ctx = valobj_sp->GetCompilerType ().GetTypeSystem <TypeSystemClang>();
144
- if (!ast_ctx)
145
- return lldb::ChildCacheState::eRefetch;
146
-
147
- // Create the `resume` and `destroy` children.
148
132
lldb::TargetSP target_sp = m_backend.GetTargetSP ();
149
133
auto &exe_ctx = m_backend.GetExecutionContextRef ();
150
134
lldb::ProcessSP process_sp = target_sp->GetProcessSP ();
151
135
auto ptr_size = process_sp->GetAddressByteSize ();
152
- CompilerType void_type = ast_ctx->GetBasicType (lldb::eBasicTypeVoid);
153
- std::array<CompilerType, 1 > args{void_type};
154
- CompilerType coro_func_type = ast_ctx->CreateFunctionType (
155
- /* result_type=*/ void_type, args,
156
- /* is_variadic=*/ false , /* qualifiers=*/ 0 );
157
- CompilerType coro_func_ptr_type = coro_func_type.GetPointerType ();
158
- m_resume_ptr_sp = CreateValueObjectFromAddress (
159
- " resume" , frame_ptr_addr + 0 * ptr_size, exe_ctx, coro_func_ptr_type);
160
- lldbassert (m_resume_ptr_sp);
161
- m_destroy_ptr_sp = CreateValueObjectFromAddress (
162
- " destroy" , frame_ptr_addr + 1 * ptr_size, exe_ctx, coro_func_ptr_type);
163
- lldbassert (m_destroy_ptr_sp);
164
-
165
- // Get the `promise_type` from the template argument
166
- CompilerType promise_type (
167
- valobj_sp->GetCompilerType ().GetTypeTemplateArgument (0 ));
168
- if (!promise_type)
136
+ auto ast_ctx = valobj_sp->GetCompilerType ().GetTypeSystem <TypeSystemClang>();
137
+ if (!ast_ctx)
169
138
return lldb::ChildCacheState::eRefetch;
170
139
171
- // Try to infer the promise_type if it was type-erased
140
+ // Determine the coroutine frame type and the promise type. Fall back
141
+ // to `void`, since even the pointer itself might be useful, even if the
142
+ // type inference failed.
143
+ Function *destroy_func = ExtractDestroyFunction (target_sp, frame_ptr_addr);
144
+ CompilerType void_type = ast_ctx->GetBasicType (lldb::eBasicTypeVoid);
145
+ CompilerType promise_type;
146
+ if (CompilerType template_argt =
147
+ valobj_sp->GetCompilerType ().GetTypeTemplateArgument (0 ))
148
+ promise_type = std::move (template_argt);
172
149
if (promise_type.IsVoidType ()) {
173
- if (Function *destroy_func =
174
- ExtractDestroyFunction (target_sp, frame_ptr_addr)) {
175
- if (CompilerType inferred_type = InferPromiseType (*destroy_func)) {
150
+ // Try to infer the promise_type if it was type-erased
151
+ if (destroy_func) {
152
+ if (CompilerType inferred_type = InferArtificialCoroType (
153
+ destroy_func, ConstString (" __promise" ))) {
176
154
promise_type = inferred_type;
177
155
}
178
156
}
179
157
}
158
+ CompilerType coro_frame_type =
159
+ InferArtificialCoroType (destroy_func, ConstString (" __coro_frame" ));
160
+ if (!coro_frame_type)
161
+ coro_frame_type = void_type;
180
162
181
- // If we don't know the promise type, we don't display the `promise` member.
182
- // `CreateValueObjectFromAddress` below would fail for `void` types.
183
- if (promise_type.IsVoidType ()) {
184
- return lldb::ChildCacheState::eRefetch;
185
- }
186
-
187
- // Add the `promise` member. We intentionally add `promise` as a pointer type
188
- // instead of a value type, and don't automatically dereference this pointer.
189
- // We do so to avoid potential very deep recursion in case there is a cycle
190
- // formed between `std::coroutine_handle`s and their promises.
191
- lldb::ValueObjectSP promise = CreateValueObjectFromAddress (
192
- " promise" , frame_ptr_addr + 2 * ptr_size, exe_ctx, promise_type);
193
- Status error;
194
- lldb::ValueObjectSP promisePtr = promise->AddressOf (error);
195
- if (error.Success ())
196
- m_promise_ptr_sp = promisePtr->Clone (ConstString (" promise" ));
163
+ // Create the `resume` and `destroy` children.
164
+ std::array<CompilerType, 1 > args{coro_frame_type};
165
+ CompilerType coro_func_type = ast_ctx->CreateFunctionType (
166
+ /* result_type=*/ void_type, args,
167
+ /* is_variadic=*/ false , /* qualifiers=*/ 0 );
168
+ CompilerType coro_func_ptr_type = coro_func_type.GetPointerType ();
169
+ ValueObjectSP resume_ptr_sp = CreateValueObjectFromAddress (
170
+ " resume" , frame_ptr_addr + 0 * ptr_size, exe_ctx, coro_func_ptr_type);
171
+ lldbassert (resume_ptr_sp);
172
+ m_children.push_back (std::move (resume_ptr_sp));
173
+ ValueObjectSP destroy_ptr_sp = CreateValueObjectFromAddress (
174
+ " destroy" , frame_ptr_addr + 1 * ptr_size, exe_ctx, coro_func_ptr_type);
175
+ lldbassert (destroy_ptr_sp);
176
+ m_children.push_back (std::move (destroy_ptr_sp));
177
+
178
+ // Add promise and coro_frame
179
+ // Add the `promise` and `coro_frame` member. We intentionally add them as
180
+ // pointer types instead of a value type, and don't automatically dereference
181
+ // those pointers. We do so to avoid potential very deep recursion in case
182
+ // there is a cycle formed between `std::coroutine_handle`s and their
183
+ // promises.
184
+ ValueObjectSP promise_ptr_sp = CreateValueObjectFromAddress (
185
+ " promise" , frame_ptr_addr + 2 * ptr_size, exe_ctx,
186
+ promise_type.GetPointerType (), /* do_deref=*/ false );
187
+ m_children.push_back (std::move (promise_ptr_sp));
188
+ ValueObjectSP coroframe_ptr_sp = CreateValueObjectFromAddress (
189
+ " coro_frame" , frame_ptr_addr, exe_ctx, coro_frame_type.GetPointerType (),
190
+ /* do_deref=*/ false );
191
+ m_children.push_back (std::move (coroframe_ptr_sp));
197
192
198
193
return lldb::ChildCacheState::eRefetch;
199
194
}
200
195
201
196
llvm::Expected<size_t >
202
197
StdlibCoroutineHandleSyntheticFrontEnd::GetIndexOfChildWithName (
203
198
ConstString name) {
204
- if (!m_resume_ptr_sp || !m_destroy_ptr_sp)
205
- return llvm::createStringError (" Type has no child named '%s'" ,
206
- name.AsCString ());
207
-
208
- if (name == ConstString (" resume" ))
209
- return 0 ;
210
- if (name == ConstString (" destroy" ))
211
- return 1 ;
212
- if (name == ConstString (" promise_ptr" ) && m_promise_ptr_sp)
213
- return 2 ;
199
+ for (size_t i = 0 , limit = m_children.size (); i < limit; ++i) {
200
+ if (m_children[i]->GetName () == name) {
201
+ return i;
202
+ }
203
+ }
214
204
215
205
return llvm::createStringError (" Type has no child named '%s'" ,
216
206
name.AsCString ());
0 commit comments