From e3b557809604d036af6e00c60f012c2025b59a5e Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: Sat, 11 Feb 2023 13:38:04 +0100 Subject: Vendor import of llvm-project main llvmorg-16-init-18548-gb0daacf58f41, the last commit before the upstream release/17.x branch was created. --- .../Python/ScriptedPythonInterface.h | 152 ++++++++++++++------- 1 file changed, 105 insertions(+), 47 deletions(-) (limited to 'lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.h') diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.h b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.h index 7c2fadc21d42..01dc07b49737 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.h +++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.h @@ -9,10 +9,15 @@ #ifndef LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTEDPYTHONINTERFACE_H #define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTEDPYTHONINTERFACE_H -#include "lldb/Host/Config.h" - #if LLDB_ENABLE_PYTHON +#include +#include +#include +#include +#include + +#include "lldb/Host/Config.h" #include "lldb/Interpreter/ScriptedInterface.h" #include "lldb/Utility/DataBufferHeap.h" @@ -34,7 +39,7 @@ protected: } template - T Dispatch(llvm::StringRef method_name, Status &error, Args... args) { + T Dispatch(llvm::StringRef method_name, Status &error, Args &&...args) { using namespace python; using Locker = ScriptInterpreterPythonImpl::Locker; @@ -56,59 +61,112 @@ protected: return ErrorWithMessage(caller_signature, "Python implementor not allocated.", error); - PythonObject pmeth( - PyRefType::Owned, - PyObject_GetAttrString(implementor.get(), method_name.str().c_str())); + std::tuple original_args = std::forward_as_tuple(args...); + auto transformed_args = TransformArgs(original_args); + + llvm::Expected expected_return_object = + llvm::make_error("Not initialized.", + llvm::inconvertibleErrorCode()); + std::apply( + [&implementor, &method_name, &expected_return_object](auto &&...args) { + llvm::consumeError(expected_return_object.takeError()); + expected_return_object = + implementor.CallMethod(method_name.data(), args...); + }, + transformed_args); + + if (llvm::Error e = expected_return_object.takeError()) { + error.SetErrorString(llvm::toString(std::move(e)).c_str()); + return ErrorWithMessage(caller_signature, + "Python method could not be called.", error); + } - if (PyErr_Occurred()) - PyErr_Clear(); + PythonObject py_return = std::move(expected_return_object.get()); - if (!pmeth.IsAllocated()) - return ErrorWithMessage(caller_signature, - "Python method not allocated.", error); + if (!py_return.IsAllocated()) + return ErrorWithMessage(caller_signature, "Returned object is null.", + error); - if (PyCallable_Check(pmeth.get()) == 0) { - if (PyErr_Occurred()) - PyErr_Clear(); - return ErrorWithMessage(caller_signature, - "Python method not callable.", 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 + // the original parameter pack as references or pointers. + if (sizeof...(Args) > 0) + if (!ReassignPtrsOrRefsArgs(original_args, transformed_args)) + return ErrorWithMessage( + caller_signature, + "Couldn't re-assign reference and pointer arguments.", error); - if (PyErr_Occurred()) - PyErr_Clear(); + return ExtractValueFromPythonObject(py_return, error); + } - // TODO: make `const char *` when removing support for Python 2. - char *format = nullptr; - std::string format_buffer; + template + Status GetStatusFromMethod(llvm::StringRef method_name, Args &&...args) { + Status error; + Dispatch(method_name, error, std::forward(args)...); - if (sizeof...(Args) > 0) { - FormatArgs(format_buffer, args...); - // TODO: make `const char *` when removing support for Python 2. - format = const_cast(format_buffer.c_str()); - } + return error; + } - // TODO: make `const char *` when removing support for Python 2. - PythonObject py_return( - PyRefType::Owned, - PyObject_CallMethod(implementor.get(), - const_cast(method_name.data()), format, - args...)); + template T Transform(T object) { + // No Transformation for generic usage + return {object}; + } - if (PyErr_Occurred()) { - PyErr_Print(); - PyErr_Clear(); - return ErrorWithMessage(caller_signature, - "Python method could not be called.", error); - } + python::PythonObject Transform(Status arg) { + return python::ToSWIGWrapper(arg); + } - if (!py_return.IsAllocated()) - return ErrorWithMessage(caller_signature, "Returned object is null.", - error); + template + void ReverseTransform(T &original_arg, U transformed_arg, Status &error) { + // If U is not a PythonObject, don't touch it! + return; + } - return ExtractValueFromPythonObject(py_return, error); + template + void ReverseTransform(T &original_arg, python::PythonObject transformed_arg, + Status &error) { + original_arg = ExtractValueFromPythonObject(transformed_arg, error); + } + + template + auto TransformTuple(const std::tuple &args, + std::index_sequence) { + return std::make_tuple(Transform(std::get(args))...); + } + + // This will iterate over the Dispatch parameter pack and replace in-place + // every `lldb_private` argument that has a SB counterpart. + template + auto TransformArgs(const std::tuple &args) { + return TransformTuple(args, std::make_index_sequence()); + } + + template + void TransformBack(T &original_arg, U transformed_arg, Status &error) { + ReverseTransform(original_arg, transformed_arg, error); } - Status GetStatusFromMethod(llvm::StringRef method_name); + template + bool ReassignPtrsOrRefsArgs(std::tuple &original_args, + std::tuple &transformed_args, + std::index_sequence) { + Status error; + (TransformBack(std::get(original_args), std::get(transformed_args), + error), + ...); + return error.Success(); + } + + template + bool ReassignPtrsOrRefsArgs(std::tuple &original_args, + std::tuple &transformed_args) { + if (sizeof...(Ts) != sizeof...(Us)) + return false; + + return ReassignPtrsOrRefsArgs(original_args, transformed_args, + std::make_index_sequence()); + } template void FormatArgs(std::string &fmt, T arg, Args... args) const { @@ -117,7 +175,7 @@ protected: } template void FormatArgs(std::string &fmt, T arg) const { - fmt += GetPythonValueFormatString(arg); + fmt += python::PythonFormat::format; } void FormatArgs(std::string &fmt) const {} @@ -146,9 +204,9 @@ ScriptedPythonInterface::ExtractValueFromPythonObject( python::PythonObject &p, Status &error); template <> -llvm::Optional +std::optional ScriptedPythonInterface::ExtractValueFromPythonObject< - llvm::Optional>(python::PythonObject &p, Status &error); + std::optional>(python::PythonObject &p, Status &error); } // namespace lldb_private -- cgit v1.3