Skip to content

Commit f22d82c

Browse files
authored
[lldb/Interpreter] Make ScriptedInterface Object creation more generic (#68052)
This patch changes the way plugin objects used with Scripted Interfaces are created. Instead of implementing a different SWIG method to create the object for every scripted interface, this patch makes the creation more generic by re-using some of the ScriptedPythonInterface templated Dispatch code. This patch also improves error handling of the object creation by returning an `llvm::Expected`. Signed-off-by: Med Ismail Bennani <[email protected]> Signed-off-by: Med Ismail Bennani <[email protected]>
1 parent 7ce613f commit f22d82c

16 files changed

+161
-153
lines changed

lldb/bindings/python/python-wrapper.swig

-43
Original file line numberDiff line numberDiff line change
@@ -229,49 +229,6 @@ PythonObject lldb_private::python::SWIGBridge::LLDBSwigPythonCreateCommandObject
229229
return pfunc(SWIGBridge::ToSWIGWrapper(std::move(debugger_sp)), dict);
230230
}
231231

232-
PythonObject lldb_private::python::SWIGBridge::LLDBSwigPythonCreateScriptedObject(
233-
const char *python_class_name, const char *session_dictionary_name,
234-
lldb::ExecutionContextRefSP exe_ctx_sp,
235-
const lldb_private::StructuredDataImpl &args_impl,
236-
std::string &error_string) {
237-
if (python_class_name == NULL || python_class_name[0] == '\0' ||
238-
!session_dictionary_name)
239-
return PythonObject();
240-
241-
PyErr_Cleaner py_err_cleaner(true);
242-
243-
auto dict = PythonModule::MainModule().ResolveName<PythonDictionary>(
244-
session_dictionary_name);
245-
auto pfunc = PythonObject::ResolveNameWithDictionary<PythonCallable>(
246-
python_class_name, dict);
247-
248-
if (!pfunc.IsAllocated()) {
249-
error_string.append("could not find script class: ");
250-
error_string.append(python_class_name);
251-
return PythonObject();
252-
}
253-
254-
llvm::Expected<PythonCallable::ArgInfo> arg_info = pfunc.GetArgInfo();
255-
if (!arg_info) {
256-
llvm::handleAllErrors(
257-
arg_info.takeError(),
258-
[&](PythonException &E) { error_string.append(E.ReadBacktrace()); },
259-
[&](const llvm::ErrorInfoBase &E) {
260-
error_string.append(E.message());
261-
});
262-
return PythonObject();
263-
}
264-
265-
PythonObject result = {};
266-
if (arg_info.get().max_positional_args == 2) {
267-
result = pfunc(SWIGBridge::ToSWIGWrapper(exe_ctx_sp), SWIGBridge::ToSWIGWrapper(args_impl));
268-
} else {
269-
error_string.assign("wrong number of arguments in __init__, should be 2 "
270-
"(not including self)");
271-
}
272-
return result;
273-
}
274-
275232
PythonObject lldb_private::python::SWIGBridge::LLDBSwigPythonCreateScriptedThreadPlan(
276233
const char *python_class_name, const char *session_dictionary_name,
277234
const lldb_private::StructuredDataImpl &args_impl,

lldb/include/lldb/Interpreter/Interfaces/ScriptedInterface.h

-5
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,6 @@ class ScriptedInterface {
2525
ScriptedInterface() = default;
2626
virtual ~ScriptedInterface() = default;
2727

28-
virtual StructuredData::GenericSP
29-
CreatePluginObject(llvm::StringRef class_name, ExecutionContext &exe_ctx,
30-
StructuredData::DictionarySP args_sp,
31-
StructuredData::Generic *script_obj = nullptr) = 0;
32-
3328
StructuredData::GenericSP GetScriptObjectInstance() {
3429
return m_object_instance_sp;
3530
}

lldb/include/lldb/Interpreter/Interfaces/ScriptedPlatformInterface.h

+4-3
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,12 @@
1919
namespace lldb_private {
2020
class ScriptedPlatformInterface : virtual public ScriptedInterface {
2121
public:
22-
StructuredData::GenericSP
22+
virtual llvm::Expected<StructuredData::GenericSP>
2323
CreatePluginObject(llvm::StringRef class_name, ExecutionContext &exe_ctx,
2424
StructuredData::DictionarySP args_sp,
25-
StructuredData::Generic *script_obj = nullptr) override {
26-
return {};
25+
StructuredData::Generic *script_obj = nullptr) {
26+
llvm_unreachable(
27+
"Cannot create an instance of the ScriptedPlatformInterface!");
2728
}
2829

2930
virtual StructuredData::DictionarySP ListProcesses() { return {}; }

lldb/include/lldb/Interpreter/Interfaces/ScriptedProcessInterface.h

+4-3
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,12 @@
2121
namespace lldb_private {
2222
class ScriptedProcessInterface : virtual public ScriptedInterface {
2323
public:
24-
StructuredData::GenericSP
24+
virtual llvm::Expected<StructuredData::GenericSP>
2525
CreatePluginObject(llvm::StringRef class_name, ExecutionContext &exe_ctx,
2626
StructuredData::DictionarySP args_sp,
27-
StructuredData::Generic *script_obj = nullptr) override {
28-
return {};
27+
StructuredData::Generic *script_obj = nullptr) {
28+
llvm_unreachable(
29+
"Cannot create an instance of the ScriptedProcessInterface!");
2930
}
3031

3132
virtual StructuredData::DictionarySP GetCapabilities() { return {}; }

lldb/include/lldb/Interpreter/Interfaces/ScriptedThreadInterface.h

+4-3
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,12 @@
2020
namespace lldb_private {
2121
class ScriptedThreadInterface : virtual public ScriptedInterface {
2222
public:
23-
StructuredData::GenericSP
23+
virtual llvm::Expected<StructuredData::GenericSP>
2424
CreatePluginObject(llvm::StringRef class_name, ExecutionContext &exe_ctx,
2525
StructuredData::DictionarySP args_sp,
26-
StructuredData::Generic *script_obj = nullptr) override {
27-
return {};
26+
StructuredData::Generic *script_obj = nullptr) {
27+
llvm_unreachable(
28+
"Cannot create an instance of the ScriptedThreadInterface!");
2829
}
2930

3031
virtual lldb::tid_t GetThreadID() { return LLDB_INVALID_THREAD_ID; }

lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp

+8-1
Original file line numberDiff line numberDiff line change
@@ -108,10 +108,17 @@ ScriptedProcess::ScriptedProcess(lldb::TargetSP target_sp,
108108
ExecutionContext exe_ctx(target_sp, /*get_process=*/false);
109109

110110
// Create process script object
111-
StructuredData::GenericSP object_sp = GetInterface().CreatePluginObject(
111+
auto obj_or_err = GetInterface().CreatePluginObject(
112112
m_scripted_metadata.GetClassName(), exe_ctx,
113113
m_scripted_metadata.GetArgsSP());
114114

115+
if (!obj_or_err) {
116+
error.SetErrorString("Failed to create script object.");
117+
return;
118+
}
119+
120+
StructuredData::GenericSP object_sp = *obj_or_err;
121+
115122
if (!object_sp || !object_sp->IsValid()) {
116123
error.SetErrorStringWithFormat("ScriptedProcess::%s () - ERROR: %s",
117124
__FUNCTION__,

lldb/source/Plugins/Process/scripted/ScriptedThread.cpp

+7-5
Original file line numberDiff line numberDiff line change
@@ -56,14 +56,16 @@ ScriptedThread::Create(ScriptedProcess &process,
5656
}
5757

5858
ExecutionContext exe_ctx(process);
59-
StructuredData::GenericSP owned_script_object_sp =
60-
scripted_thread_interface->CreatePluginObject(
61-
thread_class_name, exe_ctx, process.m_scripted_metadata.GetArgsSP(),
62-
script_object);
59+
auto obj_or_err = scripted_thread_interface->CreatePluginObject(
60+
thread_class_name, exe_ctx, process.m_scripted_metadata.GetArgsSP(),
61+
script_object);
6362

64-
if (!owned_script_object_sp)
63+
if (!obj_or_err)
6564
return llvm::createStringError(llvm::inconvertibleErrorCode(),
6665
"Failed to create script object.");
66+
67+
StructuredData::GenericSP owned_script_object_sp = *obj_or_err;
68+
6769
if (!owned_script_object_sp->IsValid())
6870
return llvm::createStringError(llvm::inconvertibleErrorCode(),
6971
"Created script object is invalid.");

lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPlatformPythonInterface.cpp

+6-20
Original file line numberDiff line numberDiff line change
@@ -29,29 +29,15 @@ ScriptedPlatformPythonInterface::ScriptedPlatformPythonInterface(
2929
ScriptInterpreterPythonImpl &interpreter)
3030
: ScriptedPlatformInterface(), ScriptedPythonInterface(interpreter) {}
3131

32-
StructuredData::GenericSP ScriptedPlatformPythonInterface::CreatePluginObject(
32+
llvm::Expected<StructuredData::GenericSP>
33+
ScriptedPlatformPythonInterface::CreatePluginObject(
3334
llvm::StringRef class_name, ExecutionContext &exe_ctx,
3435
StructuredData::DictionarySP args_sp, StructuredData::Generic *script_obj) {
35-
if (class_name.empty())
36-
return {};
37-
38-
StructuredDataImpl args_impl(args_sp);
39-
std::string error_string;
40-
41-
Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN,
42-
Locker::FreeLock);
43-
44-
lldb::ExecutionContextRefSP exe_ctx_ref_sp =
36+
ExecutionContextRefSP exe_ctx_ref_sp =
4537
std::make_shared<ExecutionContextRef>(exe_ctx);
46-
47-
PythonObject ret_val = SWIGBridge::LLDBSwigPythonCreateScriptedObject(
48-
class_name.str().c_str(), m_interpreter.GetDictionaryName(),
49-
exe_ctx_ref_sp, args_impl, error_string);
50-
51-
m_object_instance_sp =
52-
StructuredData::GenericSP(new StructuredPythonObject(std::move(ret_val)));
53-
54-
return m_object_instance_sp;
38+
StructuredDataImpl sd_impl(args_sp);
39+
return ScriptedPythonInterface::CreatePluginObject(class_name, script_obj,
40+
exe_ctx_ref_sp, sd_impl);
5541
}
5642

5743
StructuredData::DictionarySP ScriptedPlatformPythonInterface::ListProcesses() {

lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPlatformPythonInterface.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ class ScriptedPlatformPythonInterface : public ScriptedPlatformInterface,
2222
public:
2323
ScriptedPlatformPythonInterface(ScriptInterpreterPythonImpl &interpreter);
2424

25-
StructuredData::GenericSP
25+
llvm::Expected<StructuredData::GenericSP>
2626
CreatePluginObject(const llvm::StringRef class_name,
2727
ExecutionContext &exe_ctx,
2828
StructuredData::DictionarySP args_sp,

lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedProcessPythonInterface.cpp

+6-20
Original file line numberDiff line numberDiff line change
@@ -33,29 +33,15 @@ ScriptedProcessPythonInterface::ScriptedProcessPythonInterface(
3333
ScriptInterpreterPythonImpl &interpreter)
3434
: ScriptedProcessInterface(), ScriptedPythonInterface(interpreter) {}
3535

36-
StructuredData::GenericSP ScriptedProcessPythonInterface::CreatePluginObject(
36+
llvm::Expected<StructuredData::GenericSP>
37+
ScriptedProcessPythonInterface::CreatePluginObject(
3738
llvm::StringRef class_name, ExecutionContext &exe_ctx,
3839
StructuredData::DictionarySP args_sp, StructuredData::Generic *script_obj) {
39-
if (class_name.empty())
40-
return {};
41-
42-
StructuredDataImpl args_impl(args_sp);
43-
std::string error_string;
44-
45-
Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN,
46-
Locker::FreeLock);
47-
48-
lldb::ExecutionContextRefSP exe_ctx_ref_sp =
40+
ExecutionContextRefSP exe_ctx_ref_sp =
4941
std::make_shared<ExecutionContextRef>(exe_ctx);
50-
51-
PythonObject ret_val = SWIGBridge::LLDBSwigPythonCreateScriptedObject(
52-
class_name.str().c_str(), m_interpreter.GetDictionaryName(),
53-
exe_ctx_ref_sp, args_impl, error_string);
54-
55-
m_object_instance_sp =
56-
StructuredData::GenericSP(new StructuredPythonObject(std::move(ret_val)));
57-
58-
return m_object_instance_sp;
42+
StructuredDataImpl sd_impl(args_sp);
43+
return ScriptedPythonInterface::CreatePluginObject(class_name, script_obj,
44+
exe_ctx_ref_sp, sd_impl);
5945
}
6046

6147
StructuredData::DictionarySP ScriptedProcessPythonInterface::GetCapabilities() {

lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedProcessPythonInterface.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ class ScriptedProcessPythonInterface : public ScriptedProcessInterface,
2323
public:
2424
ScriptedProcessPythonInterface(ScriptInterpreterPythonImpl &interpreter);
2525

26-
StructuredData::GenericSP
26+
llvm::Expected<StructuredData::GenericSP>
2727
CreatePluginObject(const llvm::StringRef class_name,
2828
ExecutionContext &exe_ctx,
2929
StructuredData::DictionarySP args_sp,

lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h

+102-4
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,98 @@ class ScriptedPythonInterface : virtual public ScriptedInterface {
3232
ScriptedPythonInterface(ScriptInterpreterPythonImpl &interpreter);
3333
~ScriptedPythonInterface() override = default;
3434

35+
template <typename... Args>
36+
llvm::Expected<StructuredData::GenericSP>
37+
CreatePluginObject(llvm::StringRef class_name,
38+
StructuredData::Generic *script_obj, Args... args) {
39+
using namespace python;
40+
using Locker = ScriptInterpreterPythonImpl::Locker;
41+
42+
bool has_class_name = !class_name.empty();
43+
bool has_interpreter_dict =
44+
!(llvm::StringRef(m_interpreter.GetDictionaryName()).empty());
45+
if (!has_class_name && !has_interpreter_dict && !script_obj) {
46+
if (!has_class_name)
47+
return llvm::createStringError(llvm::inconvertibleErrorCode(),
48+
"Missing script class name.");
49+
else if (!has_interpreter_dict)
50+
return llvm::createStringError(
51+
llvm::inconvertibleErrorCode(),
52+
"Invalid script interpreter dictionary.");
53+
else
54+
return llvm::createStringError(llvm::inconvertibleErrorCode(),
55+
"Missing scripting object.");
56+
}
57+
58+
Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN,
59+
Locker::FreeLock);
60+
61+
PythonObject result = {};
62+
63+
if (script_obj) {
64+
result = PythonObject(PyRefType::Borrowed,
65+
static_cast<PyObject *>(script_obj->GetValue()));
66+
} else {
67+
auto dict =
68+
PythonModule::MainModule().ResolveName<python::PythonDictionary>(
69+
m_interpreter.GetDictionaryName());
70+
if (!dict.IsAllocated()) {
71+
return llvm::createStringError(
72+
llvm::inconvertibleErrorCode(),
73+
"Could not find interpreter dictionary: %s",
74+
m_interpreter.GetDictionaryName());
75+
}
76+
77+
auto method =
78+
PythonObject::ResolveNameWithDictionary<python::PythonCallable>(
79+
class_name, dict);
80+
if (!method.IsAllocated())
81+
return llvm::createStringError(llvm::inconvertibleErrorCode(),
82+
"Could not find script class: %s",
83+
class_name.data());
84+
85+
std::tuple<Args...> original_args = std::forward_as_tuple(args...);
86+
auto transformed_args = TransformArgs(original_args);
87+
88+
std::string error_string;
89+
llvm::Expected<PythonCallable::ArgInfo> arg_info = method.GetArgInfo();
90+
if (!arg_info) {
91+
llvm::handleAllErrors(
92+
arg_info.takeError(),
93+
[&](PythonException &E) { error_string.append(E.ReadBacktrace()); },
94+
[&](const llvm::ErrorInfoBase &E) {
95+
error_string.append(E.message());
96+
});
97+
return llvm::createStringError(llvm::inconvertibleErrorCode(),
98+
error_string);
99+
}
100+
101+
llvm::Expected<PythonObject> expected_return_object =
102+
llvm::createStringError(llvm::inconvertibleErrorCode(),
103+
"Resulting object is not initialized.");
104+
105+
std::apply(
106+
[&method, &expected_return_object](auto &&...args) {
107+
llvm::consumeError(expected_return_object.takeError());
108+
expected_return_object = method(args...);
109+
},
110+
transformed_args);
111+
112+
if (llvm::Error e = expected_return_object.takeError())
113+
return e;
114+
result = std::move(expected_return_object.get());
115+
}
116+
117+
if (!result.IsValid())
118+
return llvm::createStringError(
119+
llvm::inconvertibleErrorCode(),
120+
"Resulting object is not a valid Python Object.");
121+
122+
m_object_instance_sp = StructuredData::GenericSP(
123+
new StructuredPythonObject(std::move(result)));
124+
return m_object_instance_sp;
125+
}
126+
35127
protected:
36128
template <typename T = StructuredData::ObjectSP>
37129
T ExtractValueFromPythonObject(python::PythonObject &p, Status &error) {
@@ -83,10 +175,6 @@ class ScriptedPythonInterface : virtual public ScriptedInterface {
83175

84176
PythonObject py_return = std::move(expected_return_object.get());
85177

86-
if (!py_return.IsAllocated())
87-
return ErrorWithMessage<T>(caller_signature, "Returned object is null.",
88-
error);
89-
90178
// Now that we called the python method with the transformed arguments,
91179
// we need to interate again over both the original and transformed
92180
// parameter pack, and transform back the parameter that were passed in
@@ -97,6 +185,8 @@ class ScriptedPythonInterface : virtual public ScriptedInterface {
97185
caller_signature,
98186
"Couldn't re-assign reference and pointer arguments.", error);
99187

188+
if (!py_return.IsAllocated())
189+
return {};
100190
return ExtractValueFromPythonObject<T>(py_return, error);
101191
}
102192

@@ -122,6 +212,14 @@ class ScriptedPythonInterface : virtual public ScriptedInterface {
122212
return python::SWIGBridge::ToSWIGWrapper(arg);
123213
}
124214

215+
python::PythonObject Transform(const StructuredDataImpl &arg) {
216+
return python::SWIGBridge::ToSWIGWrapper(arg);
217+
}
218+
219+
python::PythonObject Transform(lldb::ExecutionContextRefSP arg) {
220+
return python::SWIGBridge::ToSWIGWrapper(arg);
221+
}
222+
125223
python::PythonObject Transform(lldb::ProcessAttachInfoSP arg) {
126224
return python::SWIGBridge::ToSWIGWrapper(arg);
127225
}

0 commit comments

Comments
 (0)