Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[lldb/Interpreter] Make ScriptedInterface Object creation more generic #68052

Merged
merged 1 commit into from
Oct 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 0 additions & 43 deletions lldb/bindings/python/python-wrapper.swig
Original file line number Diff line number Diff line change
Expand Up @@ -229,49 +229,6 @@ PythonObject lldb_private::python::SWIGBridge::LLDBSwigPythonCreateCommandObject
return pfunc(SWIGBridge::ToSWIGWrapper(std::move(debugger_sp)), dict);
}

PythonObject lldb_private::python::SWIGBridge::LLDBSwigPythonCreateScriptedObject(
const char *python_class_name, const char *session_dictionary_name,
lldb::ExecutionContextRefSP exe_ctx_sp,
const lldb_private::StructuredDataImpl &args_impl,
std::string &error_string) {
if (python_class_name == NULL || python_class_name[0] == '\0' ||
!session_dictionary_name)
return PythonObject();

PyErr_Cleaner py_err_cleaner(true);

auto dict = PythonModule::MainModule().ResolveName<PythonDictionary>(
session_dictionary_name);
auto pfunc = PythonObject::ResolveNameWithDictionary<PythonCallable>(
python_class_name, dict);

if (!pfunc.IsAllocated()) {
error_string.append("could not find script class: ");
error_string.append(python_class_name);
return PythonObject();
}

llvm::Expected<PythonCallable::ArgInfo> arg_info = pfunc.GetArgInfo();
if (!arg_info) {
llvm::handleAllErrors(
arg_info.takeError(),
[&](PythonException &E) { error_string.append(E.ReadBacktrace()); },
[&](const llvm::ErrorInfoBase &E) {
error_string.append(E.message());
});
return PythonObject();
}

PythonObject result = {};
if (arg_info.get().max_positional_args == 2) {
result = pfunc(SWIGBridge::ToSWIGWrapper(exe_ctx_sp), SWIGBridge::ToSWIGWrapper(args_impl));
} else {
error_string.assign("wrong number of arguments in __init__, should be 2 "
"(not including self)");
}
return result;
}

PythonObject lldb_private::python::SWIGBridge::LLDBSwigPythonCreateScriptedThreadPlan(
const char *python_class_name, const char *session_dictionary_name,
const lldb_private::StructuredDataImpl &args_impl,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,6 @@ class ScriptedInterface {
ScriptedInterface() = default;
virtual ~ScriptedInterface() = default;

virtual StructuredData::GenericSP
CreatePluginObject(llvm::StringRef class_name, ExecutionContext &exe_ctx,
StructuredData::DictionarySP args_sp,
StructuredData::Generic *script_obj = nullptr) = 0;

StructuredData::GenericSP GetScriptObjectInstance() {
return m_object_instance_sp;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@
namespace lldb_private {
class ScriptedPlatformInterface : virtual public ScriptedInterface {
public:
StructuredData::GenericSP
virtual llvm::Expected<StructuredData::GenericSP>
CreatePluginObject(llvm::StringRef class_name, ExecutionContext &exe_ctx,
StructuredData::DictionarySP args_sp,
StructuredData::Generic *script_obj = nullptr) override {
return {};
StructuredData::Generic *script_obj = nullptr) {
llvm_unreachable(
"Cannot create an instance of the ScriptedPlatformInterface!");
}

virtual StructuredData::DictionarySP ListProcesses() { return {}; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,12 @@
namespace lldb_private {
class ScriptedProcessInterface : virtual public ScriptedInterface {
public:
StructuredData::GenericSP
virtual llvm::Expected<StructuredData::GenericSP>
CreatePluginObject(llvm::StringRef class_name, ExecutionContext &exe_ctx,
StructuredData::DictionarySP args_sp,
StructuredData::Generic *script_obj = nullptr) override {
return {};
StructuredData::Generic *script_obj = nullptr) {
llvm_unreachable(
"Cannot create an instance of the ScriptedProcessInterface!");
}

virtual StructuredData::DictionarySP GetCapabilities() { return {}; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,12 @@
namespace lldb_private {
class ScriptedThreadInterface : virtual public ScriptedInterface {
public:
StructuredData::GenericSP
virtual llvm::Expected<StructuredData::GenericSP>
CreatePluginObject(llvm::StringRef class_name, ExecutionContext &exe_ctx,
StructuredData::DictionarySP args_sp,
StructuredData::Generic *script_obj = nullptr) override {
return {};
StructuredData::Generic *script_obj = nullptr) {
llvm_unreachable(
"Cannot create an instance of the ScriptedThreadInterface!");
}

virtual lldb::tid_t GetThreadID() { return LLDB_INVALID_THREAD_ID; }
Expand Down
9 changes: 8 additions & 1 deletion lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,10 +108,17 @@ ScriptedProcess::ScriptedProcess(lldb::TargetSP target_sp,
ExecutionContext exe_ctx(target_sp, /*get_process=*/false);

// Create process script object
StructuredData::GenericSP object_sp = GetInterface().CreatePluginObject(
auto obj_or_err = GetInterface().CreatePluginObject(
m_scripted_metadata.GetClassName(), exe_ctx,
m_scripted_metadata.GetArgsSP());

if (!obj_or_err) {
error.SetErrorString("Failed to create script object.");
return;
}

StructuredData::GenericSP object_sp = *obj_or_err;

if (!object_sp || !object_sp->IsValid()) {
error.SetErrorStringWithFormat("ScriptedProcess::%s () - ERROR: %s",
__FUNCTION__,
Expand Down
12 changes: 7 additions & 5 deletions lldb/source/Plugins/Process/scripted/ScriptedThread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,16 @@ ScriptedThread::Create(ScriptedProcess &process,
}

ExecutionContext exe_ctx(process);
StructuredData::GenericSP owned_script_object_sp =
scripted_thread_interface->CreatePluginObject(
thread_class_name, exe_ctx, process.m_scripted_metadata.GetArgsSP(),
script_object);
auto obj_or_err = scripted_thread_interface->CreatePluginObject(
thread_class_name, exe_ctx, process.m_scripted_metadata.GetArgsSP(),
script_object);

if (!owned_script_object_sp)
if (!obj_or_err)
return llvm::createStringError(llvm::inconvertibleErrorCode(),
"Failed to create script object.");

StructuredData::GenericSP owned_script_object_sp = *obj_or_err;

if (!owned_script_object_sp->IsValid())
return llvm::createStringError(llvm::inconvertibleErrorCode(),
"Created script object is invalid.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,29 +29,15 @@ ScriptedPlatformPythonInterface::ScriptedPlatformPythonInterface(
ScriptInterpreterPythonImpl &interpreter)
: ScriptedPlatformInterface(), ScriptedPythonInterface(interpreter) {}

StructuredData::GenericSP ScriptedPlatformPythonInterface::CreatePluginObject(
llvm::Expected<StructuredData::GenericSP>
ScriptedPlatformPythonInterface::CreatePluginObject(
llvm::StringRef class_name, ExecutionContext &exe_ctx,
StructuredData::DictionarySP args_sp, StructuredData::Generic *script_obj) {
if (class_name.empty())
return {};

StructuredDataImpl args_impl(args_sp);
std::string error_string;

Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN,
Locker::FreeLock);

lldb::ExecutionContextRefSP exe_ctx_ref_sp =
ExecutionContextRefSP exe_ctx_ref_sp =
std::make_shared<ExecutionContextRef>(exe_ctx);

PythonObject ret_val = SWIGBridge::LLDBSwigPythonCreateScriptedObject(
class_name.str().c_str(), m_interpreter.GetDictionaryName(),
exe_ctx_ref_sp, args_impl, error_string);

m_object_instance_sp =
StructuredData::GenericSP(new StructuredPythonObject(std::move(ret_val)));

return m_object_instance_sp;
StructuredDataImpl sd_impl(args_sp);
return ScriptedPythonInterface::CreatePluginObject(class_name, script_obj,
exe_ctx_ref_sp, sd_impl);
}

StructuredData::DictionarySP ScriptedPlatformPythonInterface::ListProcesses() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class ScriptedPlatformPythonInterface : public ScriptedPlatformInterface,
public:
ScriptedPlatformPythonInterface(ScriptInterpreterPythonImpl &interpreter);

StructuredData::GenericSP
llvm::Expected<StructuredData::GenericSP>
CreatePluginObject(const llvm::StringRef class_name,
ExecutionContext &exe_ctx,
StructuredData::DictionarySP args_sp,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,29 +33,15 @@ ScriptedProcessPythonInterface::ScriptedProcessPythonInterface(
ScriptInterpreterPythonImpl &interpreter)
: ScriptedProcessInterface(), ScriptedPythonInterface(interpreter) {}

StructuredData::GenericSP ScriptedProcessPythonInterface::CreatePluginObject(
llvm::Expected<StructuredData::GenericSP>
ScriptedProcessPythonInterface::CreatePluginObject(
llvm::StringRef class_name, ExecutionContext &exe_ctx,
StructuredData::DictionarySP args_sp, StructuredData::Generic *script_obj) {
if (class_name.empty())
return {};

StructuredDataImpl args_impl(args_sp);
std::string error_string;

Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN,
Locker::FreeLock);

lldb::ExecutionContextRefSP exe_ctx_ref_sp =
ExecutionContextRefSP exe_ctx_ref_sp =
std::make_shared<ExecutionContextRef>(exe_ctx);

PythonObject ret_val = SWIGBridge::LLDBSwigPythonCreateScriptedObject(
class_name.str().c_str(), m_interpreter.GetDictionaryName(),
exe_ctx_ref_sp, args_impl, error_string);

m_object_instance_sp =
StructuredData::GenericSP(new StructuredPythonObject(std::move(ret_val)));

return m_object_instance_sp;
StructuredDataImpl sd_impl(args_sp);
return ScriptedPythonInterface::CreatePluginObject(class_name, script_obj,
exe_ctx_ref_sp, sd_impl);
}

StructuredData::DictionarySP ScriptedProcessPythonInterface::GetCapabilities() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class ScriptedProcessPythonInterface : public ScriptedProcessInterface,
public:
ScriptedProcessPythonInterface(ScriptInterpreterPythonImpl &interpreter);

StructuredData::GenericSP
llvm::Expected<StructuredData::GenericSP>
CreatePluginObject(const llvm::StringRef class_name,
ExecutionContext &exe_ctx,
StructuredData::DictionarySP args_sp,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,98 @@ class ScriptedPythonInterface : virtual public ScriptedInterface {
ScriptedPythonInterface(ScriptInterpreterPythonImpl &interpreter);
~ScriptedPythonInterface() override = default;

template <typename... Args>
llvm::Expected<StructuredData::GenericSP>
CreatePluginObject(llvm::StringRef class_name,
StructuredData::Generic *script_obj, Args... args) {
using namespace python;
using Locker = ScriptInterpreterPythonImpl::Locker;

bool has_class_name = !class_name.empty();
bool has_interpreter_dict =
!(llvm::StringRef(m_interpreter.GetDictionaryName()).empty());
if (!has_class_name && !has_interpreter_dict && !script_obj) {
if (!has_class_name)
return llvm::createStringError(llvm::inconvertibleErrorCode(),
"Missing script class name.");
else if (!has_interpreter_dict)
return llvm::createStringError(
llvm::inconvertibleErrorCode(),
"Invalid script interpreter dictionary.");
else
return llvm::createStringError(llvm::inconvertibleErrorCode(),
"Missing scripting object.");
}

Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN,
Locker::FreeLock);

PythonObject result = {};

if (script_obj) {
result = PythonObject(PyRefType::Borrowed,
static_cast<PyObject *>(script_obj->GetValue()));
} else {
auto dict =
PythonModule::MainModule().ResolveName<python::PythonDictionary>(
m_interpreter.GetDictionaryName());
medismailben marked this conversation as resolved.
Show resolved Hide resolved
if (!dict.IsAllocated()) {
return llvm::createStringError(
llvm::inconvertibleErrorCode(),
"Could not find interpreter dictionary: %s",
m_interpreter.GetDictionaryName());
}

auto method =
PythonObject::ResolveNameWithDictionary<python::PythonCallable>(
class_name, dict);
if (!method.IsAllocated())
return llvm::createStringError(llvm::inconvertibleErrorCode(),
"Could not find script class: %s",
class_name.data());

std::tuple<Args...> original_args = std::forward_as_tuple(args...);
auto transformed_args = TransformArgs(original_args);

std::string error_string;
llvm::Expected<PythonCallable::ArgInfo> arg_info = method.GetArgInfo();
if (!arg_info) {
llvm::handleAllErrors(
arg_info.takeError(),
[&](PythonException &E) { error_string.append(E.ReadBacktrace()); },
[&](const llvm::ErrorInfoBase &E) {
error_string.append(E.message());
});
return llvm::createStringError(llvm::inconvertibleErrorCode(),
error_string);
}

llvm::Expected<PythonObject> expected_return_object =
llvm::createStringError(llvm::inconvertibleErrorCode(),
"Resulting object is not initialized.");

std::apply(
[&method, &expected_return_object](auto &&...args) {
llvm::consumeError(expected_return_object.takeError());
expected_return_object = method(args...);
},
transformed_args);

if (llvm::Error e = expected_return_object.takeError())
return e;
result = std::move(expected_return_object.get());
}

if (!result.IsValid())
return llvm::createStringError(
llvm::inconvertibleErrorCode(),
"Resulting object is not a valid Python Object.");

m_object_instance_sp = StructuredData::GenericSP(
new StructuredPythonObject(std::move(result)));
return m_object_instance_sp;
}

protected:
template <typename T = StructuredData::ObjectSP>
T ExtractValueFromPythonObject(python::PythonObject &p, Status &error) {
Expand Down Expand Up @@ -83,10 +175,6 @@ class ScriptedPythonInterface : virtual public ScriptedInterface {

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

if (!py_return.IsAllocated())
return ErrorWithMessage<T>(caller_signature, "Returned object is null.",
error);

// Now that we called the python method with the transformed arguments,
// we need to interate again over both the original and transformed
// parameter pack, and transform back the parameter that were passed in
Expand All @@ -97,6 +185,8 @@ class ScriptedPythonInterface : virtual public ScriptedInterface {
caller_signature,
"Couldn't re-assign reference and pointer arguments.", error);

if (!py_return.IsAllocated())
return {};
return ExtractValueFromPythonObject<T>(py_return, error);
}

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

python::PythonObject Transform(const StructuredDataImpl &arg) {
return python::SWIGBridge::ToSWIGWrapper(arg);
}

python::PythonObject Transform(lldb::ExecutionContextRefSP arg) {
return python::SWIGBridge::ToSWIGWrapper(arg);
}

python::PythonObject Transform(lldb::ProcessAttachInfoSP arg) {
return python::SWIGBridge::ToSWIGWrapper(arg);
}
Expand Down
Loading
Loading