Skip to content

Commit 785c0b2

Browse files
authored
Merge pull request #5793 from augusto2112/bind-many-self-params-0
[lldb] Make generic expr eval work with multiple toplevel generic params
2 parents d6f66df + 09e6631 commit 785c0b2

File tree

8 files changed

+414
-188
lines changed

8 files changed

+414
-188
lines changed

lldb/source/Plugins/ExpressionParser/Swift/SwiftASTManipulator.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,9 @@ class SwiftASTManipulatorBase {
9191
swift::VarDecl::Introducer GetVarIntroducer() const;
9292
bool GetIsCaptureList() const;
9393
bool IsMetadataPointer() const { return m_name.str().startswith(""); }
94+
bool IsOutermostMetadataPointer() const {
95+
return m_name.str().startswith("$τ_0_");
96+
}
9497
bool IsSelf() const {
9598
return !m_name.str().compare("$__lldb_injected_self");
9699
}

lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionParser.cpp

Lines changed: 39 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -503,24 +503,6 @@ lldb::VariableSP SwiftExpressionParser::FindSelfVariable(Block *block) {
503503
return variable_list_sp->FindVariable(ConstString("self"));
504504
}
505505

506-
struct BindGenericSelfParamsError : public llvm::ErrorInfo<BindGenericSelfParamsError> {
507-
static char ID;
508-
std::string msg;
509-
bool is_new_dylib;
510-
511-
BindGenericSelfParamsError() = default;
512-
513-
void log(llvm::raw_ostream &OS) const override {
514-
OS << "Couldn't realize Swift AST type of self. Hint: using `v` to "
515-
"directly inspect variables and fields may still work.";
516-
}
517-
std::error_code convertToErrorCode() const override {
518-
return inconvertibleErrorCode();
519-
}
520-
};
521-
522-
char BindGenericSelfParamsError::ID = 0;
523-
524506
static void AddRequiredAliases(Block *block, lldb::StackFrameSP &stack_frame_sp,
525507
SwiftASTContextForExpressions &swift_ast_context,
526508
SwiftASTManipulator &manipulator,
@@ -1075,9 +1057,10 @@ static llvm::Expected<ParsedExpression> ParseAndImport(
10751057
DiagnosticManager &diagnostic_manager,
10761058
SwiftExpressionParser &swift_expr_parser,
10771059
lldb::StackFrameWP &stack_frame_wp, SymbolContext &sc,
1078-
ExecutionContextScope &exe_scope,
1079-
llvm::SmallVector<SwiftASTManipulator::VariableInfo> &local_variables,
1080-
const EvaluateExpressionOptions &options, bool repl, bool playground) {
1060+
ExecutionContextScope &exe_scope,
1061+
llvm::SmallVectorImpl<SwiftASTManipulator::VariableInfo> &local_variables,
1062+
const EvaluateExpressionOptions &options,
1063+
bool repl, bool playground) {
10811064
Log *log = GetLog(LLDBLog::Expressions);
10821065
LLDB_SCOPED_TIMER();
10831066

@@ -1385,19 +1368,27 @@ RedirectCallFromSinkToTrampolineFunction(llvm::Module &module,
13851368
}
13861369

13871370
auto *trampoline_func_type = trampoline_func->getFunctionType();
1388-
auto num_params = trampoline_func_type->getNumParams();
1389-
// There should be 3 params, the raw pointer, the self type, and the pointer
1390-
// to metadata
1391-
if (num_params != 3) {
1371+
auto trampoline_num_params = trampoline_func_type->getNumParams();
1372+
// There should be at least 3 params, the raw pointer, the self type, and at
1373+
// least one pointer to metadata.
1374+
if (trampoline_num_params < 3) {
13921375
log->Printf(
13931376
"[RedirectCallFromSinkToTrampolineFunction] Could not set the call: "
13941377
"trampoline function has %u parameters",
1395-
num_params);
1378+
trampoline_num_params);
13961379
return false;
13971380
}
13981381

1399-
llvm::Type *param1 = trampoline_func_type->getParamType(1);
1400-
llvm::Type *param2 = trampoline_func_type->getParamType(2);
1382+
auto *sink_func_type = sink_func->getFunctionType();
1383+
auto sink_num_params = sink_func_type->getNumParams();
1384+
1385+
if (trampoline_num_params != sink_num_params) {
1386+
log->Printf(
1387+
"[RedirectCallFromSinkToTrampolineFunction] Could not set the call: "
1388+
"trampoline function has %u parameters but sink has %u parameters.",
1389+
trampoline_num_params, sink_num_params);
1390+
return false;
1391+
}
14011392

14021393
auto &basic_blocks = lldb_expr_func->getBasicBlockList();
14031394
// The entrypoint function should only have one basic block whith
@@ -1436,18 +1427,22 @@ RedirectCallFromSinkToTrampolineFunction(llvm::Module &module,
14361427
return false;
14371428
}
14381429

1439-
if (sink_call->arg_size() != 3) {
1430+
if (sink_call->arg_size() != sink_num_params) {
14401431
log->Printf(
14411432
"[RedirectCallFromSinkToTrampolineFunction] Could not set the call: "
14421433
"call to sink function has %u arguments.",
14431434
sink_call->arg_size());
14441435
return false;
14451436
}
1446-
// The sink call should have three parameters, the pointer to lldb_arg, a
1447-
// pointer to self and a pointer to the trampoline metadata of self.
1437+
1438+
// The sink call should have at least three parameters, the pointer to
1439+
// lldb_arg, a pointer to self and a pointer to the trampoline metadata of
1440+
// self.
14481441
llvm::Value *lldb_arg_ptr = sink_call->getArgOperand(0);
14491442
llvm::Value *self_load = sink_call->getArgOperand(1);
1450-
llvm::Value *metadata_load = sink_call->getArgOperand(2);
1443+
llvm::SmallVector<llvm::Value *> metadata_loads;
1444+
for (size_t i = 2; i < sink_num_params; ++i)
1445+
metadata_loads.emplace_back(sink_call->getArgOperand(i));
14511446

14521447
// Delete the sink since we fished out the values we needed.
14531448
sink_call->eraseFromParent();
@@ -1469,14 +1464,23 @@ RedirectCallFromSinkToTrampolineFunction(llvm::Module &module,
14691464
// new call there.
14701465
llvm::IRBuilder<> builder(&it);
14711466

1467+
llvm::Type *lldb_arg_type = trampoline_func_type->getParamType(1);
1468+
llvm::Type *self_type = trampoline_func_type->getParamType(2);
1469+
14721470
// Bitcast the operands to the expected types, since they were type-erased
14731471
// in the call to the sink.
1474-
auto *self_ptr = builder.CreateBitCast(self_opaque_ptr, param1);
1475-
auto *metadata_ptr = builder.CreateBitCast(metadata_load, param2);
1472+
auto *self_ptr = builder.CreateBitCast(self_opaque_ptr, lldb_arg_type);
1473+
1474+
llvm::SmallVector<llvm::Value *> trampoline_call_params;
1475+
trampoline_call_params.push_back(lldb_arg_ptr);
1476+
trampoline_call_params.push_back(self_ptr);
1477+
for (auto &metadata_load : metadata_loads)
1478+
trampoline_call_params.push_back(
1479+
builder.CreateBitCast(metadata_load, self_type));
14761480

14771481
// Finally, create the call.
14781482
builder.CreateCall(trampoline_func_type, trampoline_func,
1479-
{lldb_arg_ptr, self_ptr, metadata_ptr});
1483+
trampoline_call_params);
14801484
return true;
14811485
}
14821486

@@ -1512,7 +1516,6 @@ SwiftExpressionParser::Parse(DiagnosticManager &diagnostic_manager,
15121516

15131517
if (!parsed_expr) {
15141518
bool retry = false;
1515-
bool bind_gen_params_error = false;
15161519
handleAllErrors(
15171520
parsed_expr.takeError(),
15181521
[&](const ModuleImportError &MIE) {
@@ -1538,14 +1541,8 @@ SwiftExpressionParser::Parse(DiagnosticManager &diagnostic_manager,
15381541
diagnostic_manager.PutString(eDiagnosticSeverityError,
15391542
SE.getMessage());
15401543
},
1541-
[&](const BindGenericSelfParamsError &E) {
1542-
diagnostic_manager.PutString(eDiagnosticSeverityError, E.message());
1543-
bind_gen_params_error = true;
1544-
},
15451544
[](const PropagatedError &P) {});
15461545

1547-
if (bind_gen_params_error)
1548-
return ParseResult::retry_no_bind_generic_params;
15491546
// Signal that we want to retry the expression exactly once with a
15501547
// fresh SwiftASTContext initialized with the flags from the
15511548
// current lldb::Module / Swift dylib to avoid header search

lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionSourceCode.cpp

Lines changed: 109 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,96 @@ static const char *GetUserCodeStartMarker() {
2626
}
2727
static const char *GetUserCodeEndMarker() { return "\n/*__LLDB_USER_END__*/"; }
2828

29-
static void WrapExpression(lldb_private::Stream &wrapped_stream,
30-
const char *orig_text, bool needs_object_ptr,
31-
bool static_method, bool is_class, bool weak_self,
32-
const EvaluateExpressionOptions &options,
33-
llvm::StringRef os_version,
34-
uint32_t &first_body_line) {
29+
30+
struct CallsAndArgs {
31+
std::string lldb_user_expr;
32+
std::string lldb_trampoline;
33+
std::string lldb_sink;
34+
std::string lldb_call;
35+
};
36+
37+
/// Constructs the signatures for the expression evaluation functions based on
38+
/// the metadata variables in scope.
39+
/// For every outermost metadata pointer in scope ($τ_0_0, $τ_0_1, etc), we want
40+
/// to generate:
41+
///
42+
/// - A $__lldb_user_expr signature that takes in that many metadata pointers:
43+
///
44+
/// func $__lldb_user_expr<T0, T1, ..., Tn>
45+
/// (_ $__lldb_arg: UnsafeMutablePointer<(T0, T1, ..., Tn)>)
46+
///
47+
/// - A $__lldb_trampoline signature like the above, but that also takes in a
48+
/// pointer to self:
49+
///
50+
/// func $__lldb_trampoline<T0, T1, ..., Tn>
51+
/// (_ $__lldb_arg: UnsafeMutablePointer<(T0, T1, ..., Tn)>,
52+
/// _ $__lldb_injected_self: inout $__lldb_context)
53+
///
54+
/// - A $__lldb_sink signature that matches the number of parameters of the
55+
/// trampoline:
56+
///
57+
/// func $__lldb_sink(_ $__lldb_arg : UnsafeMutablePointer<Any>,
58+
/// _: $__lldb_builtin_ptr_t, // the self variable
59+
/// _: $__lldb_builtin_ptr_t, // T0
60+
/// _: $__lldb_builtin_ptr_t, // T1
61+
/// ...,
62+
/// _: $__lldb_builtin_ptr_t) // Tn
63+
///
64+
/// - And a matching call to the sink function:
65+
///
66+
/// lldb_sink($__lldb_arg, $__lldb_injected_self, $τ_0_0, $τ_0_1, ..., $τ_0_n)
67+
static CallsAndArgs MakeGenericSignaturesAndCalls(
68+
llvm::ArrayRef<SwiftASTManipulator::VariableInfo> local_variables) {
69+
llvm::SmallVector<SwiftASTManipulator::VariableInfo> metadata_variables;
70+
for (auto &var : local_variables)
71+
if (var.IsOutermostMetadataPointer())
72+
metadata_variables.push_back(var);
73+
74+
std::string generic_param_list;
75+
llvm::raw_string_ostream generic_param_list_stream(generic_param_list);
76+
for (size_t i = 0; i < metadata_variables.size(); ++i)
77+
generic_param_list_stream << "T" << i << ",";
78+
79+
if (!generic_param_list.empty())
80+
generic_param_list.pop_back();
81+
82+
std::string user_expr;
83+
llvm::raw_string_ostream user_expr_stream(user_expr);
84+
user_expr_stream << "func $__lldb_user_expr<" << generic_param_list
85+
<< ">(_ $__lldb_arg: UnsafeMutablePointer<("
86+
<< generic_param_list << ")>)";
87+
88+
89+
std::string trampoline;
90+
llvm::raw_string_ostream trampoline_stream(trampoline);
91+
trampoline_stream << "func $__lldb_trampoline<" << generic_param_list
92+
<< ">(_ $__lldb_arg: UnsafeMutablePointer<("
93+
<< generic_param_list
94+
<< ")>, _ $__lldb_injected_self: inout $__lldb_context)";
95+
96+
std::string sink;
97+
std::string call;
98+
llvm::raw_string_ostream sink_stream(sink);
99+
llvm::raw_string_ostream call_stream(call);
100+
sink_stream << "func $__lldb_sink(_ $__lldb_arg : "
101+
"UnsafeMutablePointer<Any>, _: $__lldb_builtin_ptr_t";
102+
call_stream << "$__lldb_sink($__lldb_arg, $__lldb_injected_self";
103+
for (auto &var : metadata_variables) {
104+
sink_stream << ", _: $__lldb_builtin_ptr_t";
105+
call_stream << ", " << var.GetName().str();
106+
}
107+
sink_stream << ")";
108+
call_stream << ")";
109+
110+
return {user_expr, trampoline, sink, call};
111+
}
112+
113+
void WrapExpression(
114+
lldb_private::Stream &wrapped_stream, const char *orig_text,
115+
bool needs_object_ptr, bool static_method, bool is_class, bool weak_self,
116+
const EvaluateExpressionOptions &options, llvm::StringRef os_version,
117+
uint32_t &first_body_line,
118+
llvm::ArrayRef<SwiftASTManipulator::VariableInfo> local_variables) {
35119
first_body_line = 0; // set to invalid
36120
// TODO make the extension private so we're not polluting the class
37121
static unsigned int counter = 0;
@@ -142,7 +226,8 @@ do {
142226
}
143227
)",
144228
GetUserCodeStartMarker(), text,
145-
GetUserCodeEndMarker(), SwiftASTManipulator::GetErrorName());
229+
GetUserCodeEndMarker(),
230+
SwiftASTManipulator::GetErrorName());
146231

147232
if (needs_object_ptr || static_method) {
148233
const char *func_decorator = "";
@@ -201,41 +286,41 @@ do {
201286
// FIXME: the current approach names the generic parameter "T", use the
202287
// user's name for the generic parameter, so they can refer to it in
203288
// their expression.
289+
auto c = MakeGenericSignaturesAndCalls(local_variables);
204290
wrapped_stream.Printf(
205291
R"(
206292
extension %s$__lldb_context {
207293
@LLDBDebuggerFunction %s
208-
%s func $__lldb_user_expr_%u<T>(_ $__lldb_arg: UnsafeMutablePointer<(T)>) {
294+
%s %s {
209295
%s
210296
}
211297
}
212298
213299
@LLDBDebuggerFunction %s
214-
func $__lldb_trampoline<T>(_ $__lldb_arg: UnsafeMutablePointer<(T)>,
215-
_ $__lldb_injected_self: inout $__lldb_context) {
300+
%s {
216301
do {
217-
$__lldb_injected_self.$__lldb_user_expr_%u(
302+
$__lldb_injected_self.$__lldb_user_expr(
218303
$__lldb_arg
219304
)
220305
}
221306
}
222307
223308
224309
@LLDBDebuggerFunction %s
225-
func $__lldb_sink(_ $__lldb_arg : UnsafeMutablePointer<Any>,
226-
_: $__lldb_builtin_ptr_t,
227-
_: $__lldb_builtin_ptr_t) {
310+
%s {
228311
}
229312
230313
231314
@LLDBDebuggerFunction %s
232315
func $__lldb_expr(_ $__lldb_arg : UnsafeMutablePointer<Any>) {
233-
$__lldb_sink($__lldb_arg, $__lldb_injected_self, $τ_0_0)
316+
%s
234317
}
235318
)",
236319
optional_extension, availability.c_str(), func_decorator,
237-
current_counter, wrapped_expr_text.GetData(), availability.c_str(),
238-
current_counter, availability.c_str(), availability.c_str());
320+
c.lldb_user_expr.c_str(), wrapped_expr_text.GetData(),
321+
availability.c_str(), c.lldb_trampoline.c_str(),
322+
availability.c_str(), c.lldb_sink.c_str(), availability.c_str(),
323+
c.lldb_call.c_str());
239324

240325
} else {
241326
wrapped_stream.Printf(R"(
@@ -270,6 +355,7 @@ func $__lldb_expr(_ $__lldb_arg : UnsafeMutablePointer<Any>) {
270355
first_body_line = 4;
271356
}
272357
}
358+
273359
/// Format the OS name the way that Swift availability attributes do.
274360
static llvm::StringRef getAvailabilityName(const llvm::Triple &triple) {
275361
swift::LangOptions lang_options;
@@ -285,16 +371,11 @@ uint32_t SwiftExpressionSourceCode::GetNumBodyLines() {
285371
}
286372

287373
bool SwiftExpressionSourceCode::GetText(
288-
std::string &text,
289-
lldb::LanguageType wrapping_language,
290-
bool needs_object_ptr,
291-
bool static_method,
292-
bool is_class,
293-
bool weak_self,
294-
const EvaluateExpressionOptions &options,
295-
ExecutionContext &exe_ctx,
296-
uint32_t &first_body_line) const
297-
{
374+
std::string &text, lldb::LanguageType wrapping_language,
375+
bool needs_object_ptr, bool static_method, bool is_class, bool weak_self,
376+
const EvaluateExpressionOptions &options, ExecutionContext &exe_ctx,
377+
uint32_t &first_body_line,
378+
llvm::ArrayRef<SwiftASTManipulator::VariableInfo> local_variables) const {
298379
Target *target = exe_ctx.GetTargetPtr();
299380

300381

@@ -364,7 +445,7 @@ bool SwiftExpressionSourceCode::GetText(
364445
std::string full_body = m_prefix + m_body;
365446
WrapExpression(wrap_stream, full_body.c_str(), needs_object_ptr,
366447
static_method, is_class, weak_self, localOptions,
367-
os_vers.str(), first_body_line);
448+
os_vers.str(), first_body_line, local_variables);
368449

369450
text = wrap_stream.GetString().str();
370451
} else {

lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionSourceCode.h

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#ifndef liblldb_SwiftExpressionSourceCode_h
1010
#define liblldb_SwiftExpressionSourceCode_h
1111

12+
#include "SwiftASTManipulator.h"
1213
#include "lldb/Expression/Expression.h"
1314
#include "lldb/Expression/ExpressionSourceCode.h"
1415
#include "lldb/lldb-enumerations.h"
@@ -36,15 +37,12 @@ class SwiftExpressionSourceCode : public ExpressionSourceCode {
3637

3738
uint32_t GetNumBodyLines();
3839

39-
bool GetText(std::string &text,
40-
lldb::LanguageType wrapping_language,
41-
bool needs_object_ptr,
42-
bool static_method,
43-
bool is_class,
44-
bool weak_self,
45-
const EvaluateExpressionOptions &options,
46-
ExecutionContext &exe_ctx,
47-
uint32_t &first_body_line) const;
40+
bool GetText(
41+
std::string &text, lldb::LanguageType wrapping_language,
42+
bool needs_object_ptr, bool static_method, bool is_class, bool weak_self,
43+
const EvaluateExpressionOptions &options, ExecutionContext &exe_ctx,
44+
uint32_t &first_body_line,
45+
llvm::ArrayRef<SwiftASTManipulator::VariableInfo> local_variables) const;
4846

4947
private:
5048
SwiftExpressionSourceCode(const char *name, const char *prefix, const char *body,

0 commit comments

Comments
 (0)