xref: /llvm-project/lldb/source/Plugins/Language/CPlusPlus/Coroutines.cpp (revision 91389000abe8ef5d06d98cbbefd3fa03ac7e4480)
1 //===-- Coroutines.cpp ----------------------------------------------------===//
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 "Coroutines.h"
10 
11 #include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
12 
13 using namespace lldb;
14 using namespace lldb_private;
15 using namespace lldb_private::formatters;
16 
17 static ValueObjectSP GetCoroFramePtrFromHandle(ValueObject &valobj) {
18   ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue());
19   if (!valobj_sp)
20     return nullptr;
21 
22   // We expect a single pointer in the `coroutine_handle` class.
23   // We don't care about its name.
24   if (valobj_sp->GetNumChildren() != 1)
25     return nullptr;
26   ValueObjectSP ptr_sp(valobj_sp->GetChildAtIndex(0, true));
27   if (!ptr_sp)
28     return nullptr;
29   if (!ptr_sp->GetCompilerType().IsPointerType())
30     return nullptr;
31 
32   return ptr_sp;
33 }
34 
35 static CompilerType GetCoroutineFrameType(TypeSystemClang &ast_ctx,
36                                           CompilerType promise_type) {
37   CompilerType void_type = ast_ctx.GetBasicType(lldb::eBasicTypeVoid);
38   CompilerType coro_func_type = ast_ctx.CreateFunctionType(
39       /*result_type=*/void_type, /*args=*/&void_type, /*num_args=*/1,
40       /*is_variadic=*/false, /*qualifiers=*/0);
41   CompilerType coro_abi_type;
42   if (promise_type.IsVoidType()) {
43     coro_abi_type = ast_ctx.CreateStructForIdentifier(
44         ConstString(), {{"resume", coro_func_type.GetPointerType()},
45                         {"destroy", coro_func_type.GetPointerType()}});
46   } else {
47     coro_abi_type = ast_ctx.CreateStructForIdentifier(
48         ConstString(), {{"resume", coro_func_type.GetPointerType()},
49                         {"destroy", coro_func_type.GetPointerType()},
50                         {"promise", promise_type}});
51   }
52   return coro_abi_type;
53 }
54 
55 bool lldb_private::formatters::StdlibCoroutineHandleSummaryProvider(
56     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
57   ValueObjectSP ptr_sp(GetCoroFramePtrFromHandle(valobj));
58   if (!ptr_sp)
59     return false;
60 
61   stream.Printf("coro frame = 0x%" PRIx64, ptr_sp->GetValueAsUnsigned(0));
62   return true;
63 }
64 
65 lldb_private::formatters::StdlibCoroutineHandleSyntheticFrontEnd::
66     StdlibCoroutineHandleSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
67     : SyntheticChildrenFrontEnd(*valobj_sp) {
68   if (valobj_sp)
69     Update();
70 }
71 
72 lldb_private::formatters::StdlibCoroutineHandleSyntheticFrontEnd::
73     ~StdlibCoroutineHandleSyntheticFrontEnd() = default;
74 
75 size_t lldb_private::formatters::StdlibCoroutineHandleSyntheticFrontEnd::
76     CalculateNumChildren() {
77   if (!m_frame_ptr_sp)
78     return 0;
79 
80   return m_frame_ptr_sp->GetNumChildren();
81 }
82 
83 lldb::ValueObjectSP lldb_private::formatters::
84     StdlibCoroutineHandleSyntheticFrontEnd::GetChildAtIndex(size_t idx) {
85   if (!m_frame_ptr_sp)
86     return lldb::ValueObjectSP();
87 
88   return m_frame_ptr_sp->GetChildAtIndex(idx, true);
89 }
90 
91 bool lldb_private::formatters::StdlibCoroutineHandleSyntheticFrontEnd::
92     Update() {
93   m_frame_ptr_sp.reset();
94 
95   ValueObjectSP valobj_sp = m_backend.GetSP();
96   if (!valobj_sp)
97     return false;
98 
99   ValueObjectSP ptr_sp(GetCoroFramePtrFromHandle(m_backend));
100   if (!ptr_sp)
101     return false;
102 
103   TypeSystemClang *ast_ctx = llvm::dyn_cast_or_null<TypeSystemClang>(
104       valobj_sp->GetCompilerType().GetTypeSystem());
105   if (!ast_ctx)
106     return false;
107 
108   CompilerType promise_type(
109       valobj_sp->GetCompilerType().GetTypeTemplateArgument(0));
110   if (!promise_type)
111     return false;
112   CompilerType coro_frame_type = GetCoroutineFrameType(*ast_ctx, promise_type);
113 
114   m_frame_ptr_sp = ptr_sp->Cast(coro_frame_type.GetPointerType());
115 
116   return false;
117 }
118 
119 bool lldb_private::formatters::StdlibCoroutineHandleSyntheticFrontEnd::
120     MightHaveChildren() {
121   return true;
122 }
123 
124 size_t StdlibCoroutineHandleSyntheticFrontEnd::GetIndexOfChildWithName(
125     ConstString name) {
126   if (!m_frame_ptr_sp)
127     return UINT32_MAX;
128 
129   return m_frame_ptr_sp->GetIndexOfChildWithName(name);
130 }
131 
132 SyntheticChildrenFrontEnd *
133 lldb_private::formatters::StdlibCoroutineHandleSyntheticFrontEndCreator(
134     CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
135   return (valobj_sp ? new StdlibCoroutineHandleSyntheticFrontEnd(valobj_sp)
136                     : nullptr);
137 }
138