From 04edd1893c2d0f35880fd5f81e78dc23979df0b9 Mon Sep 17 00:00:00 2001 From: Lawrence D'Anna Date: Tue, 22 Oct 2019 02:32:37 +0000 Subject: remove multi-argument form of PythonObject::Reset() Summary: With this patch, only the no-argument form of `Reset()` remains in PythonDataObjects. It also deletes PythonExceptionState in favor of PythonException, because the only call-site of PythonExceptionState was also using Reset, so I cleaned up both while I was there. Reviewers: JDevlieghere, clayborg, labath, jingham Reviewed By: labath Subscribers: mgorny, lldb-commits Tags: #lldb Differential Revision: https://reviews.llvm.org/D69214 llvm-svn: 375475 --- .../ScriptInterpreter/Python/PythonDataObjects.h | 115 +++++++++++++-------- 1 file changed, 73 insertions(+), 42 deletions(-) (limited to 'lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h') diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h b/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h index 634d6e89601..373d3212697 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h +++ b/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h @@ -59,6 +59,7 @@ #include "llvm/ADT/ArrayRef.h" namespace lldb_private { +namespace python { class PythonObject; class PythonBytes; @@ -113,7 +114,6 @@ enum class PyRefType { // not call Py_INCREF. }; -namespace python { // Take a reference that you already own, and turn it into // a PythonObject. @@ -175,7 +175,19 @@ public: operator const char *() { return str; } }; -} // namespace python +inline llvm::Error nullDeref() { + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "A NULL PyObject* was dereferenced"); +} + +inline llvm::Error exception(const char *s = nullptr) { + return llvm::make_error(s); +} + +inline llvm::Error keyError() { + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "key not in dict"); +} enum class PyInitialValue { Invalid, Empty }; @@ -191,6 +203,11 @@ template <> struct PythonFormat { static auto get(long long value) { return value; } }; +template <> struct PythonFormat { + static constexpr char format = 'O'; + static auto get(PyObject *value) { return value; } +}; + template struct PythonFormat< T, typename std::enable_if::value>::type> { @@ -202,8 +219,14 @@ class PythonObject { public: PythonObject() : m_py_obj(nullptr) {} - PythonObject(PyRefType type, PyObject *py_obj) : m_py_obj(nullptr) { - Reset(type, py_obj); + PythonObject(PyRefType type, PyObject *py_obj) { + m_py_obj = py_obj; + // If this is a borrowed reference, we need to convert it to + // an owned reference by incrementing it. If it is an owned + // reference (for example the caller allocated it with PyDict_New() + // then we must *not* increment it. + if (m_py_obj && Py_IsInitialized() && type == PyRefType::Borrowed) + Py_XINCREF(m_py_obj); } PythonObject(const PythonObject &rhs) @@ -222,23 +245,6 @@ public: m_py_obj = nullptr; } - void Reset(PyRefType type, PyObject *py_obj) { - if (py_obj == m_py_obj) - return; - - if (Py_IsInitialized()) - Py_XDECREF(m_py_obj); - - m_py_obj = py_obj; - - // If this is a borrowed reference, we need to convert it to - // an owned reference by incrementing it. If it is an owned - // reference (for example the caller allocated it with PyDict_New() - // then we must *not* increment it. - if (m_py_obj && Py_IsInitialized() && type == PyRefType::Borrowed) - Py_XINCREF(m_py_obj); - } - void Dump() const { if (m_py_obj) _PyObject_Dump(m_py_obj); @@ -304,17 +310,6 @@ public: StructuredData::ObjectSP CreateStructuredObject() const; protected: - static llvm::Error nullDeref() { - return llvm::createStringError(llvm::inconvertibleErrorCode(), - "A NULL PyObject* was dereferenced"); - } - static llvm::Error exception(const char *s = nullptr) { - return llvm::make_error(s); - } - static llvm::Error keyError() { - return llvm::createStringError(llvm::inconvertibleErrorCode(), - "key not in dict"); - } #if PY_MAJOR_VERSION < 3 // The python 2 API declares some arguments as char* that should @@ -348,7 +343,6 @@ public: } llvm::Expected GetAttribute(const llvm::Twine &name) const { - using namespace python; if (!m_py_obj) return nullDeref(); PyObject *obj = PyObject_GetAttrString(m_py_obj, NullTerminated(name)); @@ -389,7 +383,6 @@ protected: PyObject *m_py_obj; }; -namespace python { // This is why C++ needs monads. template llvm::Expected As(llvm::Expected &&obj) { @@ -409,7 +402,6 @@ llvm::Expected As(llvm::Expected &&obj); template <> llvm::Expected As(llvm::Expected &&obj); -} // namespace python template class TypedPythonObject : public PythonObject { public: @@ -417,16 +409,12 @@ public: // This can be eliminated once we drop python 2 support. static void Convert(PyRefType &type, PyObject *&py_obj) {} - void Reset() { PythonObject::Reset(); } - - void Reset(PyRefType type, PyObject *py_obj) = delete; - TypedPythonObject(PyRefType type, PyObject *py_obj) { if (!py_obj) return; T::Convert(type, py_obj); if (T::Check(py_obj)) - PythonObject::Reset(type, py_obj); + PythonObject::operator=(PythonObject(type, py_obj)); else if (type == PyRefType::Owned) Py_DECREF(py_obj); } @@ -698,6 +686,8 @@ public: ~PythonException(); void log(llvm::raw_ostream &OS) const override; std::error_code convertToErrorCode() const override; + bool Matches(PyObject *exc) const; + std::string ReadBacktrace() const; }; // This extracts the underlying T out of an Expected and returns it. @@ -732,7 +722,6 @@ template T unwrapOrSetPythonException(llvm::Expected expected) { return T(); } -namespace python { // This is only here to help incrementally migrate old, exception-unsafe // code. template T unwrapIgnoringErrors(llvm::Expected expected) { @@ -741,8 +730,50 @@ template T unwrapIgnoringErrors(llvm::Expected expected) { llvm::consumeError(expected.takeError()); return T(); } -} // namespace python +llvm::Expected runStringOneLine(const llvm::Twine &string, + const PythonDictionary &globals, + const PythonDictionary &locals); + +llvm::Expected runStringMultiLine(const llvm::Twine &string, + const PythonDictionary &globals, + const PythonDictionary &locals); + +// Sometimes the best way to interact with a python interpreter is +// to run some python code. You construct a PythonScript with +// script string. The script assigns some function to `_function_` +// and you get a C++ callable object that calls the python function. +// +// Example: +// +// const char script[] = R"( +// def main(x, y): +// .... +// )"; +// +// Expected cpp_foo_wrapper(PythonObject x, PythonObject y) { +// // no need to synchronize access to this global, we already have the GIL +// static PythonScript foo(script) +// return foo(x, y); +// } +class PythonScript { + const char *script; + PythonCallable function; + + llvm::Error Init(); + +public: + PythonScript(const char *script) : script(script), function() {} + + template + llvm::Expected operator()(Args &&... args) { + if (llvm::Error error = Init()) + return std::move(error); + return function.Call(std::forward(args)...); + } +}; + +} // namespace python } // namespace lldb_private #endif -- cgit v1.2.3