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,23 @@ 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) {
66
- Block &block = destroy_func.GetBlock (true );
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) {
67
+ if (!destroy_func)
68
+ return {};
69
+
70
+ Block &block = destroy_func->GetBlock (true );
67
71
auto variable_list = block.GetBlockVariableList (true );
68
72
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)
73
+ auto var = variable_list->FindVariable (var_name);
74
+ if (!var)
73
75
return {};
74
- if (!promise_var ->IsArtificial ())
76
+ if (!var ->IsArtificial ())
75
77
return {};
76
78
77
- Type *promise_type = promise_var ->GetType ();
79
+ Type *promise_type = var ->GetType ();
78
80
if (!promise_type)
79
81
return {};
80
82
return promise_type->GetForwardCompilerType ();
@@ -108,30 +110,17 @@ lldb_private::formatters::StdlibCoroutineHandleSyntheticFrontEnd::
108
110
109
111
llvm::Expected<uint32_t > lldb_private::formatters::
110
112
StdlibCoroutineHandleSyntheticFrontEnd::CalculateNumChildren () {
111
- if (!m_resume_ptr_sp || !m_destroy_ptr_sp)
112
- return 0 ;
113
-
114
- return m_promise_ptr_sp ? 3 : 2 ;
113
+ return m_children.size ();
115
114
}
116
115
117
116
lldb::ValueObjectSP lldb_private::formatters::
118
117
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 ();
118
+ return idx < m_children.size () ? m_children[idx] : lldb::ValueObjectSP ();
128
119
}
129
120
130
121
lldb::ChildCacheState
131
122
lldb_private::formatters::StdlibCoroutineHandleSyntheticFrontEnd::Update () {
132
- m_resume_ptr_sp.reset ();
133
- m_destroy_ptr_sp.reset ();
134
- m_promise_ptr_sp.reset ();
123
+ m_children.clear ();
135
124
136
125
ValueObjectSP valobj_sp = m_backend.GetNonSyntheticValue ();
137
126
if (!valobj_sp)
@@ -141,76 +130,77 @@ lldb_private::formatters::StdlibCoroutineHandleSyntheticFrontEnd::Update() {
141
130
if (frame_ptr_addr == 0 || frame_ptr_addr == LLDB_INVALID_ADDRESS)
142
131
return lldb::ChildCacheState::eRefetch;
143
132
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
133
lldb::TargetSP target_sp = m_backend.GetTargetSP ();
150
134
auto &exe_ctx = m_backend.GetExecutionContextRef ();
151
135
lldb::ProcessSP process_sp = target_sp->GetProcessSP ();
152
136
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)
137
+ auto ast_ctx = valobj_sp->GetCompilerType ().GetTypeSystem <TypeSystemClang>();
138
+ if (!ast_ctx)
169
139
return lldb::ChildCacheState::eRefetch;
170
140
171
- // Try to infer the promise_type if it was type-erased
141
+ // Determine the coroutine frame type and the promise type. Fall back
142
+ // to `void`, since even the pointer itself might be useful, even if the
143
+ // type inference failed.
144
+ Function *destroy_func = ExtractDestroyFunction (target_sp, frame_ptr_addr);
145
+ CompilerType void_type = ast_ctx->GetBasicType (lldb::eBasicTypeVoid);
146
+ CompilerType promise_type;
147
+ if (CompilerType template_argt =
148
+ valobj_sp->GetCompilerType ().GetTypeTemplateArgument (0 ))
149
+ promise_type = std::move (template_argt);
172
150
if (promise_type.IsVoidType ()) {
173
- if (Function *destroy_func =
174
- ExtractDestroyFunction (target_sp, frame_ptr_addr)) {
175
- if (CompilerType inferred_type = InferPromiseType (*destroy_func)) {
151
+ // Try to infer the promise_type if it was type-erased
152
+ if (destroy_func) {
153
+ if (CompilerType inferred_type = InferArtificialCoroType (
154
+ destroy_func, ConstString (" __promise" ))) {
176
155
promise_type = inferred_type;
177
156
}
178
157
}
179
158
}
159
+ CompilerType coro_frame_type =
160
+ InferArtificialCoroType (destroy_func, ConstString (" __coro_frame" ));
161
+ if (!coro_frame_type)
162
+ coro_frame_type = void_type;
180
163
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" ));
164
+ // Create the `resume` and `destroy` children.
165
+ CompilerType coro_func_type = ast_ctx->CreateFunctionType (
166
+ /* result_type=*/ void_type, /* args=*/ &coro_frame_type, /* num_args=*/ 1 ,
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