diff options
author | Lawrence D'Anna <lawrence_danna@apple.com> | 2019-10-22 02:32:37 +0000 |
---|---|---|
committer | Lawrence D'Anna <lawrence_danna@apple.com> | 2019-10-22 02:32:37 +0000 |
commit | 04edd1893c2d0f35880fd5f81e78dc23979df0b9 (patch) | |
tree | 3cf81a16415feb717f0c566e804a8ddbdb87db06 /lldb/source/Plugins/ScriptInterpreter/Python | |
parent | b94ac8a2632968d3961d528faa75d68a517b3bc4 (diff) | |
download | bcm5719-llvm-04edd1893c2d0f35880fd5f81e78dc23979df0b9.tar.gz bcm5719-llvm-04edd1893c2d0f35880fd5f81e78dc23979df0b9.zip |
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
Diffstat (limited to 'lldb/source/Plugins/ScriptInterpreter/Python')
7 files changed, 316 insertions, 479 deletions
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt b/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt index 2c5071bc765..54b5c236f75 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt +++ b/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt @@ -5,7 +5,6 @@ add_definitions(-DLLDB_PYTHON_RELATIVE_LIBDIR="${LLDB_PYTHON_RELATIVE_PATH}") add_lldb_library(lldbPluginScriptInterpreterPython PLUGIN PythonDataObjects.cpp - PythonExceptionState.cpp ScriptInterpreterPython.cpp LINK_LIBS diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp index d0d593656ef..70d93424fde 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp +++ b/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp @@ -261,8 +261,7 @@ size_t PythonBytes::GetSize() const { void PythonBytes::SetBytes(llvm::ArrayRef<uint8_t> bytes) { const char *data = reinterpret_cast<const char *>(bytes.data()); - PyObject *py_bytes = PyBytes_FromStringAndSize(data, bytes.size()); - PythonObject::Reset(PyRefType::Owned, py_bytes); + *this = Take<PythonBytes>(PyBytes_FromStringAndSize(data, bytes.size())); } StructuredData::StringSP PythonBytes::CreateStructuredString() const { @@ -486,7 +485,7 @@ int64_t PythonInteger::GetInteger() const { } void PythonInteger::SetInteger(int64_t value) { - PythonObject::Reset(PyRefType::Owned, PyLong_FromLongLong(value)); + *this = Take<PythonInteger>(PyLong_FromLongLong(value)); } StructuredData::IntegerSP PythonInteger::CreateStructuredInteger() const { @@ -510,7 +509,7 @@ bool PythonBoolean::GetValue() const { } void PythonBoolean::SetValue(bool value) { - PythonObject::Reset(PyRefType::Owned, PyBool_FromLong(value)); + *this = Take<PythonBoolean>(PyBool_FromLong(value)); } StructuredData::BooleanSP PythonBoolean::CreateStructuredBoolean() const { @@ -826,7 +825,7 @@ static const char get_arg_info_script[] = R"( from inspect import signature, Parameter, ismethod from collections import namedtuple ArgInfo = namedtuple('ArgInfo', ['count', 'has_varargs', 'is_bound_method']) -def get_arg_info(f): +def main(f): count = 0 varargs = False for parameter in signature(f).parameters.values(): @@ -852,28 +851,9 @@ Expected<PythonCallable::ArgInfo> PythonCallable::GetArgInfo() const { #if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 3 - // this global is protected by the GIL - static PythonCallable get_arg_info; - - if (!get_arg_info.IsValid()) { - PythonDictionary globals(PyInitialValue::Empty); - - auto builtins = PythonModule::BuiltinsModule(); - Error error = globals.SetItem("__builtins__", builtins); - if (error) - return std::move(error); - PyObject *o = PyRun_String(get_arg_info_script, Py_file_input, - globals.get(), globals.get()); - if (!o) - return exception(); - Take<PythonObject>(o); - auto function = As<PythonCallable>(globals.GetItem("get_arg_info")); - if (!function) - return function.takeError(); - get_arg_info = std::move(function.get()); - } - - Expected<PythonObject> pyarginfo = get_arg_info.Call(*this); + // no need to synchronize access to this global, we already have the GIL + static PythonScript get_arg_info(get_arg_info_script); + Expected<PythonObject> pyarginfo = get_arg_info(*this); if (!pyarginfo) return pyarginfo.takeError(); result.count = cantFail(As<long long>(pyarginfo.get().GetAttribute("count"))); @@ -1056,6 +1036,44 @@ std::error_code PythonException::convertToErrorCode() const { return llvm::inconvertibleErrorCode(); } +bool PythonException::Matches(PyObject *exc) const { + return PyErr_GivenExceptionMatches(m_exception_type, exc); +} + +const char read_exception_script[] = R"( +import sys +from traceback import print_exception +if sys.version_info.major < 3: + from StringIO import StringIO +else: + from io import StringIO +def main(exc_type, exc_value, tb): + f = StringIO() + print_exception(exc_type, exc_value, tb, file=f) + return f.getvalue() +)"; + +std::string PythonException::ReadBacktrace() const { + + if (!m_traceback) + return toCString(); + + // no need to synchronize access to this global, we already have the GIL + static PythonScript read_exception(read_exception_script); + + Expected<std::string> backtrace = As<std::string>( + read_exception(m_exception_type, m_exception, m_traceback)); + + if (!backtrace) { + std::string message = + std::string(toCString()) + "\n" + + "Traceback unavailble, an error occurred while reading it:\n"; + return (message + llvm::toString(backtrace.takeError())); + } + + return std::move(backtrace.get()); +} + char PythonException::ID = 0; llvm::Expected<File::OpenOptions> @@ -1496,4 +1514,69 @@ Expected<PythonFile> PythonFile::FromFile(File &file, const char *mode) { return Take<PythonFile>(file_obj); } +Error PythonScript::Init() { + if (function.IsValid()) + return Error::success(); + + PythonDictionary globals(PyInitialValue::Empty); + auto builtins = PythonModule::BuiltinsModule(); + if (Error error = globals.SetItem("__builtins__", builtins)) + return error; + PyObject *o = + PyRun_String(script, Py_file_input, globals.get(), globals.get()); + if (!o) + return exception(); + Take<PythonObject>(o); + auto f = As<PythonCallable>(globals.GetItem("main")); + if (!f) + return f.takeError(); + function = std::move(f.get()); + + return Error::success(); +} + +llvm::Expected<PythonObject> +python::runStringOneLine(const llvm::Twine &string, + const PythonDictionary &globals, + const PythonDictionary &locals) { + if (!globals.IsValid() || !locals.IsValid()) + return nullDeref(); + + PyObject *code = + Py_CompileString(NullTerminated(string), "<string>", Py_eval_input); + if (!code) { + PyErr_Clear(); + code = + Py_CompileString(NullTerminated(string), "<string>", Py_single_input); + } + if (!code) + return exception(); + auto code_ref = Take<PythonObject>(code); + +#if PY_MAJOR_VERSION < 3 + PyObject *result = + PyEval_EvalCode((PyCodeObject *)code, globals.get(), locals.get()); +#else + PyObject *result = PyEval_EvalCode(code, globals.get(), locals.get()); +#endif + + if (!result) + return exception(); + + return Take<PythonObject>(result); +} + +llvm::Expected<PythonObject> +python::runStringMultiLine(const llvm::Twine &string, + const PythonDictionary &globals, + const PythonDictionary &locals) { + if (!globals.IsValid() || !locals.IsValid()) + return nullDeref(); + PyObject *result = PyRun_String(NullTerminated(string), Py_file_input, + globals.get(), locals.get()); + if (!result) + return exception(); + return Take<PythonObject>(result); +} + #endif 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<PythonException>(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<long long> { static auto get(long long value) { return value; } }; +template <> struct PythonFormat<PyObject *> { + static constexpr char format = 'O'; + static auto get(PyObject *value) { return value; } +}; + template <typename T> struct PythonFormat< T, typename std::enable_if<std::is_base_of<PythonObject, T>::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<PythonException>(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<PythonObject> 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 <typename T> llvm::Expected<T> As(llvm::Expected<PythonObject> &&obj) { @@ -409,7 +402,6 @@ llvm::Expected<long long> As<long long>(llvm::Expected<PythonObject> &&obj); template <> llvm::Expected<std::string> As<std::string>(llvm::Expected<PythonObject> &&obj); -} // namespace python template <class T> 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<T> and returns it. @@ -732,7 +722,6 @@ template <typename T> T unwrapOrSetPythonException(llvm::Expected<T> expected) { return T(); } -namespace python { // This is only here to help incrementally migrate old, exception-unsafe // code. template <typename T> T unwrapIgnoringErrors(llvm::Expected<T> expected) { @@ -741,8 +730,50 @@ template <typename T> T unwrapIgnoringErrors(llvm::Expected<T> expected) { llvm::consumeError(expected.takeError()); return T(); } -} // namespace python +llvm::Expected<PythonObject> runStringOneLine(const llvm::Twine &string, + const PythonDictionary &globals, + const PythonDictionary &locals); + +llvm::Expected<PythonObject> 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<PythonObject> 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 <typename... Args> + llvm::Expected<PythonObject> operator()(Args &&... args) { + if (llvm::Error error = Init()) + return std::move(error); + return function.Call(std::forward<Args>(args)...); + } +}; + +} // namespace python } // namespace lldb_private #endif diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/PythonExceptionState.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/PythonExceptionState.cpp deleted file mode 100644 index c9d834ce686..00000000000 --- a/lldb/source/Plugins/ScriptInterpreter/Python/PythonExceptionState.cpp +++ /dev/null @@ -1,169 +0,0 @@ -//===-- PythonExceptionState.cpp --------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLDB_DISABLE_PYTHON - -// LLDB Python header must be included first -#include "lldb-python.h" - -#include "PythonExceptionState.h" - -#include "llvm/ADT/StringRef.h" -#include "llvm/Support/raw_ostream.h" - -using namespace lldb_private; - -PythonExceptionState::PythonExceptionState(bool restore_on_exit) - : m_restore_on_exit(restore_on_exit) { - Acquire(restore_on_exit); -} - -PythonExceptionState::~PythonExceptionState() { - if (m_restore_on_exit) - Restore(); -} - -void PythonExceptionState::Acquire(bool restore_on_exit) { - // If a state is already acquired, the user needs to decide whether they want - // to discard or restore it. Don't allow the potential silent loss of a - // valid state. - assert(!IsError()); - - if (!HasErrorOccurred()) - return; - - PyObject *py_type = nullptr; - PyObject *py_value = nullptr; - PyObject *py_traceback = nullptr; - PyErr_Fetch(&py_type, &py_value, &py_traceback); - // PyErr_Fetch clears the error flag. - assert(!HasErrorOccurred()); - - // Ownership of the objects returned by `PyErr_Fetch` is transferred to us. - m_type.Reset(PyRefType::Owned, py_type); - m_value.Reset(PyRefType::Owned, py_value); - m_traceback.Reset(PyRefType::Owned, py_traceback); - m_restore_on_exit = restore_on_exit; -} - -void PythonExceptionState::Restore() { - if (m_type.IsValid()) { - // The documentation for PyErr_Restore says "Do not pass a null type and - // non-null value or traceback. So only restore if type was non-null to - // begin with. In this case we're passing ownership back to Python so - // release them all. - PyErr_Restore(m_type.release(), m_value.release(), m_traceback.release()); - } - - // After we restore, we should not hold onto the exception state. Demand - // that it be re-acquired. - Discard(); -} - -void PythonExceptionState::Discard() { - m_type.Reset(); - m_value.Reset(); - m_traceback.Reset(); -} - -void PythonExceptionState::Reset() { - if (m_restore_on_exit) - Restore(); - else - Discard(); -} - -bool PythonExceptionState::HasErrorOccurred() { return PyErr_Occurred(); } - -bool PythonExceptionState::IsError() const { - return m_type.IsValid() || m_value.IsValid() || m_traceback.IsValid(); -} - -PythonObject PythonExceptionState::GetType() const { return m_type; } - -PythonObject PythonExceptionState::GetValue() const { return m_value; } - -PythonObject PythonExceptionState::GetTraceback() const { return m_traceback; } - -std::string PythonExceptionState::Format() const { - // Don't allow this function to modify the error state. - PythonExceptionState state(true); - - std::string backtrace = ReadBacktrace(); - if (!IsError()) - return std::string(); - - // It's possible that ReadPythonBacktrace generated another exception. If - // this happens we have to clear the exception, because otherwise - // PyObject_Str() will assert below. That's why we needed to do the save / - // restore at the beginning of this function. - PythonExceptionState bt_error_state(false); - - std::string error_string; - llvm::raw_string_ostream error_stream(error_string); - error_stream << m_value.Str().GetString() << "\n"; - - if (!bt_error_state.IsError()) { - // If we were able to read the backtrace, just append it. - error_stream << backtrace << "\n"; - } else { - // Otherwise, append some information about why we were unable to obtain - // the backtrace. - PythonString bt_error = bt_error_state.GetValue().Str(); - error_stream << "An error occurred while retrieving the backtrace: " - << bt_error.GetString() << "\n"; - } - return error_stream.str(); -} - -std::string PythonExceptionState::ReadBacktrace() const { - std::string retval("backtrace unavailable"); - - auto traceback_module = PythonModule::ImportModule("traceback"); -#if PY_MAJOR_VERSION >= 3 - auto stringIO_module = PythonModule::ImportModule("io"); -#else - auto stringIO_module = PythonModule::ImportModule("StringIO"); -#endif - if (!m_traceback.IsAllocated()) - return retval; - - if (!traceback_module.IsAllocated() || !stringIO_module.IsAllocated()) - return retval; - - auto stringIO_builder = - stringIO_module.ResolveName<PythonCallable>("StringIO"); - if (!stringIO_builder.IsAllocated()) - return retval; - - auto stringIO_buffer = stringIO_builder(); - if (!stringIO_buffer.IsAllocated()) - return retval; - - auto printTB = traceback_module.ResolveName<PythonCallable>("print_tb"); - if (!printTB.IsAllocated()) - return retval; - - auto printTB_result = - printTB(m_traceback.get(), Py_None, stringIO_buffer.get()); - auto stringIO_getvalue = - stringIO_buffer.ResolveName<PythonCallable>("getvalue"); - if (!stringIO_getvalue.IsAllocated()) - return retval; - - auto printTB_string = stringIO_getvalue().AsType<PythonString>(); - if (!printTB_string.IsAllocated()) - return retval; - - llvm::StringRef string_data(printTB_string.GetString()); - retval.assign(string_data.data(), string_data.size()); - - return retval; -} - -#endif diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/PythonExceptionState.h b/lldb/source/Plugins/ScriptInterpreter/Python/PythonExceptionState.h deleted file mode 100644 index 3a88aa03777..00000000000 --- a/lldb/source/Plugins/ScriptInterpreter/Python/PythonExceptionState.h +++ /dev/null @@ -1,56 +0,0 @@ -//===-- PythonExceptionState.h ----------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_PYTHONEXCEPTIONSTATE_H -#define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_PYTHONEXCEPTIONSTATE_H - -#ifndef LLDB_DISABLE_PYTHON - -#include "PythonDataObjects.h" - -namespace lldb_private { - -class PythonExceptionState { -public: - explicit PythonExceptionState(bool restore_on_exit); - ~PythonExceptionState(); - - void Acquire(bool restore_on_exit); - - void Restore(); - - void Discard(); - - void Reset(); - - static bool HasErrorOccurred(); - - bool IsError() const; - - PythonObject GetType() const; - - PythonObject GetValue() const; - - PythonObject GetTraceback() const; - - std::string Format() const; - -private: - std::string ReadBacktrace() const; - - bool m_restore_on_exit; - - PythonObject m_type; - PythonObject m_value; - PythonObject m_traceback; -}; -} - -#endif - -#endif diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp index 8f713352416..3eee5218414 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp +++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp @@ -16,7 +16,6 @@ #include "lldb-python.h" #include "PythonDataObjects.h" -#include "PythonExceptionState.h" #include "ScriptInterpreterPythonImpl.h" #include "lldb/API/SBFrame.h" @@ -56,6 +55,7 @@ using namespace lldb; using namespace lldb_private; using namespace lldb_private::python; +using llvm::Expected; // Defined in the SWIG source file #if PY_MAJOR_VERSION >= 3 @@ -747,9 +747,9 @@ bool ScriptInterpreterPythonImpl::EnterSession(uint16_t on_entry_flags, return true; } -PythonObject &ScriptInterpreterPythonImpl::GetMainModule() { +PythonModule &ScriptInterpreterPythonImpl::GetMainModule() { if (!m_main_module.IsValid()) - m_main_module.Reset(PyRefType::Borrowed, PyImport_AddModule("__main__")); + m_main_module = unwrapIgnoringErrors(PythonModule::Import("__main__")); return m_main_module; } @@ -1030,6 +1030,7 @@ bool ScriptInterpreterPythonImpl::Interrupt() { "can't interrupt"); return false; } + bool ScriptInterpreterPythonImpl::ExecuteOneLineWithReturn( llvm::StringRef in_string, ScriptInterpreter::ScriptReturnType return_type, void *ret_value, const ExecuteScriptOptions &options) { @@ -1040,151 +1041,111 @@ bool ScriptInterpreterPythonImpl::ExecuteOneLineWithReturn( Locker::NoSTDIN, Locker::FreeAcquiredLock | Locker::TearDownSession); - PythonObject py_return; - PythonObject &main_module = GetMainModule(); - PythonDictionary globals(PyRefType::Borrowed, - PyModule_GetDict(main_module.get())); - PythonObject py_error; - bool ret_success = false; - int success; + PythonModule &main_module = GetMainModule(); + PythonDictionary globals = main_module.GetDictionary(); PythonDictionary locals = GetSessionDictionary(); - - if (!locals.IsValid()) { + if (!locals.IsValid()) locals = unwrapIgnoringErrors( As<PythonDictionary>(globals.GetAttribute(m_dictionary_name))); - } - if (!locals.IsValid()) locals = globals; - py_error.Reset(PyRefType::Borrowed, PyErr_Occurred()); - if (py_error.IsValid()) - PyErr_Clear(); - - std::string as_string = in_string.str(); - { // scope for PythonInputReaderManager - // PythonInputReaderManager py_input(options.GetEnableIO() ? this : NULL); - py_return.Reset(PyRefType::Owned, - PyRun_String(as_string.c_str(), Py_eval_input, - globals.get(), locals.get())); - if (!py_return.IsValid()) { - py_error.Reset(PyRefType::Borrowed, PyErr_Occurred()); - if (py_error.IsValid()) - PyErr_Clear(); - - py_return.Reset(PyRefType::Owned, - PyRun_String(as_string.c_str(), Py_single_input, - globals.get(), locals.get())); - } + Expected<PythonObject> maybe_py_return = + runStringOneLine(in_string, globals, locals); + + if (!maybe_py_return) { + llvm::handleAllErrors( + maybe_py_return.takeError(), + [&](PythonException &E) { + E.Restore(); + if (options.GetMaskoutErrors()) { + if (E.Matches(PyExc_SyntaxError)) { + PyErr_Print(); + } + PyErr_Clear(); + } + }, + [](const llvm::ErrorInfoBase &E) {}); + return false; } - if (py_return.IsValid()) { - switch (return_type) { - case eScriptReturnTypeCharPtr: // "char *" - { - const char format[3] = "s#"; - success = PyArg_Parse(py_return.get(), format, (char **)ret_value); - break; - } - case eScriptReturnTypeCharStrOrNone: // char* or NULL if py_return == - // Py_None - { - const char format[3] = "z"; - success = PyArg_Parse(py_return.get(), format, (char **)ret_value); - break; - } - case eScriptReturnTypeBool: { - const char format[2] = "b"; - success = PyArg_Parse(py_return.get(), format, (bool *)ret_value); - break; - } - case eScriptReturnTypeShortInt: { - const char format[2] = "h"; - success = PyArg_Parse(py_return.get(), format, (short *)ret_value); - break; - } - case eScriptReturnTypeShortIntUnsigned: { - const char format[2] = "H"; - success = - PyArg_Parse(py_return.get(), format, (unsigned short *)ret_value); - break; - } - case eScriptReturnTypeInt: { - const char format[2] = "i"; - success = PyArg_Parse(py_return.get(), format, (int *)ret_value); - break; - } - case eScriptReturnTypeIntUnsigned: { - const char format[2] = "I"; - success = PyArg_Parse(py_return.get(), format, (unsigned int *)ret_value); - break; - } - case eScriptReturnTypeLongInt: { - const char format[2] = "l"; - success = PyArg_Parse(py_return.get(), format, (long *)ret_value); - break; - } - case eScriptReturnTypeLongIntUnsigned: { - const char format[2] = "k"; - success = - PyArg_Parse(py_return.get(), format, (unsigned long *)ret_value); - break; - } - case eScriptReturnTypeLongLong: { - const char format[2] = "L"; - success = PyArg_Parse(py_return.get(), format, (long long *)ret_value); - break; - } - case eScriptReturnTypeLongLongUnsigned: { - const char format[2] = "K"; - success = - PyArg_Parse(py_return.get(), format, (unsigned long long *)ret_value); - break; - } - case eScriptReturnTypeFloat: { - const char format[2] = "f"; - success = PyArg_Parse(py_return.get(), format, (float *)ret_value); - break; - } - case eScriptReturnTypeDouble: { - const char format[2] = "d"; - success = PyArg_Parse(py_return.get(), format, (double *)ret_value); - break; - } - case eScriptReturnTypeChar: { - const char format[2] = "c"; - success = PyArg_Parse(py_return.get(), format, (char *)ret_value); - break; - } - case eScriptReturnTypeOpaqueObject: { - success = true; - PyObject *saved_value = py_return.get(); - Py_XINCREF(saved_value); - *((PyObject **)ret_value) = saved_value; - break; - } - } + PythonObject py_return = std::move(maybe_py_return.get()); + assert(py_return.IsValid()); - ret_success = success; + switch (return_type) { + case eScriptReturnTypeCharPtr: // "char *" + { + const char format[3] = "s#"; + return PyArg_Parse(py_return.get(), format, (char **)ret_value); + } + case eScriptReturnTypeCharStrOrNone: // char* or NULL if py_return == + // Py_None + { + const char format[3] = "z"; + return PyArg_Parse(py_return.get(), format, (char **)ret_value); + } + case eScriptReturnTypeBool: { + const char format[2] = "b"; + return PyArg_Parse(py_return.get(), format, (bool *)ret_value); + } + case eScriptReturnTypeShortInt: { + const char format[2] = "h"; + return PyArg_Parse(py_return.get(), format, (short *)ret_value); + } + case eScriptReturnTypeShortIntUnsigned: { + const char format[2] = "H"; + return PyArg_Parse(py_return.get(), format, (unsigned short *)ret_value); + } + case eScriptReturnTypeInt: { + const char format[2] = "i"; + return PyArg_Parse(py_return.get(), format, (int *)ret_value); + } + case eScriptReturnTypeIntUnsigned: { + const char format[2] = "I"; + return PyArg_Parse(py_return.get(), format, (unsigned int *)ret_value); + } + case eScriptReturnTypeLongInt: { + const char format[2] = "l"; + return PyArg_Parse(py_return.get(), format, (long *)ret_value); + } + case eScriptReturnTypeLongIntUnsigned: { + const char format[2] = "k"; + return PyArg_Parse(py_return.get(), format, (unsigned long *)ret_value); + } + case eScriptReturnTypeLongLong: { + const char format[2] = "L"; + return PyArg_Parse(py_return.get(), format, (long long *)ret_value); + } + case eScriptReturnTypeLongLongUnsigned: { + const char format[2] = "K"; + return PyArg_Parse(py_return.get(), format, + (unsigned long long *)ret_value); + } + case eScriptReturnTypeFloat: { + const char format[2] = "f"; + return PyArg_Parse(py_return.get(), format, (float *)ret_value); + } + case eScriptReturnTypeDouble: { + const char format[2] = "d"; + return PyArg_Parse(py_return.get(), format, (double *)ret_value); + } + case eScriptReturnTypeChar: { + const char format[2] = "c"; + return PyArg_Parse(py_return.get(), format, (char *)ret_value); + } + case eScriptReturnTypeOpaqueObject: { + *((PyObject **)ret_value) = py_return.release(); + return true; } - - py_error.Reset(PyRefType::Borrowed, PyErr_Occurred()); - if (py_error.IsValid()) { - ret_success = false; - if (options.GetMaskoutErrors()) { - if (PyErr_GivenExceptionMatches(py_error.get(), PyExc_SyntaxError)) - PyErr_Print(); - PyErr_Clear(); - } } - - return ret_success; } Status ScriptInterpreterPythonImpl::ExecuteMultipleLines( const char *in_string, const ExecuteScriptOptions &options) { - Status error; + + if (in_string == nullptr) + return Status(); Locker locker(this, Locker::AcquireLock | Locker::InitSession | @@ -1192,51 +1153,32 @@ Status ScriptInterpreterPythonImpl::ExecuteMultipleLines( Locker::NoSTDIN, Locker::FreeAcquiredLock | Locker::TearDownSession); - PythonObject return_value; - PythonObject &main_module = GetMainModule(); - PythonDictionary globals(PyRefType::Borrowed, - PyModule_GetDict(main_module.get())); - PythonObject py_error; + PythonModule &main_module = GetMainModule(); + PythonDictionary globals = main_module.GetDictionary(); PythonDictionary locals = GetSessionDictionary(); - if (!locals.IsValid()) locals = unwrapIgnoringErrors( As<PythonDictionary>(globals.GetAttribute(m_dictionary_name))); - if (!locals.IsValid()) locals = globals; - py_error.Reset(PyRefType::Borrowed, PyErr_Occurred()); - if (py_error.IsValid()) - PyErr_Clear(); - - if (in_string != nullptr) { - PythonObject code_object; - code_object.Reset(PyRefType::Owned, - Py_CompileString(in_string, "temp.py", Py_file_input)); + Expected<PythonObject> return_value = + runStringMultiLine(in_string, globals, locals); - if (code_object.IsValid()) { -// In Python 2.x, PyEval_EvalCode takes a PyCodeObject, but in Python 3.x, it -// takes a PyObject. They are convertible (hence the function -// PyCode_Check(PyObject*), so we have to do the cast for Python 2.x -#if PY_MAJOR_VERSION >= 3 - PyObject *py_code_obj = code_object.get(); -#else - PyCodeObject *py_code_obj = - reinterpret_cast<PyCodeObject *>(code_object.get()); -#endif - return_value.Reset( - PyRefType::Owned, - PyEval_EvalCode(py_code_obj, globals.get(), locals.get())); - } + if (!return_value) { + llvm::Error error = + llvm::handleErrors(return_value.takeError(), [&](PythonException &E) { + llvm::Error error = llvm::createStringError( + llvm::inconvertibleErrorCode(), E.ReadBacktrace()); + if (!options.GetMaskoutErrors()) + E.Restore(); + return error; + }); + return Status(std::move(error)); } - PythonExceptionState exception_state(!options.GetMaskoutErrors()); - if (exception_state.IsError()) - error.SetErrorString(exception_state.Format().c_str()); - - return error; + return Status(); } void ScriptInterpreterPythonImpl::CollectDataForBreakpointCommandCallback( @@ -2030,15 +1972,22 @@ StructuredData::DictionarySP ScriptInterpreterPythonImpl::GetDynamicSettings( if (!generic) return StructuredData::DictionarySP(); - PythonObject reply_pyobj; Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); TargetSP target_sp(target->shared_from_this()); - reply_pyobj.Reset(PyRefType::Owned, - (PyObject *)LLDBSWIGPython_GetDynamicSetting( - generic->GetValue(), setting_name, target_sp)); - PythonDictionary py_dict(PyRefType::Borrowed, reply_pyobj.get()); + auto setting = (PyObject *)LLDBSWIGPython_GetDynamicSetting( + generic->GetValue(), setting_name, target_sp); + + if (!setting) + return StructuredData::DictionarySP(); + + PythonDictionary py_dict = + unwrapIgnoringErrors(As<PythonDictionary>(Take<PythonObject>(setting))); + + if (!py_dict) + return StructuredData::DictionarySP(); + return py_dict.CreateStructuredDictionary(); } diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h index 373513f8e47..929567e579d 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h +++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h @@ -363,25 +363,25 @@ public: eIOHandlerWatchpoint }; - PythonObject &GetMainModule(); + python::PythonModule &GetMainModule(); - PythonDictionary &GetSessionDictionary(); + python::PythonDictionary &GetSessionDictionary(); - PythonDictionary &GetSysModuleDictionary(); + python::PythonDictionary &GetSysModuleDictionary(); bool GetEmbeddedInterpreterModuleObjects(); bool SetStdHandle(lldb::FileSP file, const char *py_name, - PythonObject &save_file, const char *mode); - - PythonObject m_saved_stdin; - PythonObject m_saved_stdout; - PythonObject m_saved_stderr; - PythonObject m_main_module; - PythonDictionary m_session_dict; - PythonDictionary m_sys_module_dict; - PythonObject m_run_one_line_function; - PythonObject m_run_one_line_str_global; + python::PythonObject &save_file, const char *mode); + + python::PythonObject m_saved_stdin; + python::PythonObject m_saved_stdout; + python::PythonObject m_saved_stderr; + python::PythonModule m_main_module; + python::PythonDictionary m_session_dict; + python::PythonDictionary m_sys_module_dict; + python::PythonObject m_run_one_line_function; + python::PythonObject m_run_one_line_str_global; std::string m_dictionary_name; ActiveIOHandler m_active_io_handler; bool m_session_is_active; |