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