Re-land "get rid of PythonInteger::GetInteger()"

This was reverted due to a python2-specific bug.  Re-landing with a fix
for python2.

Summary:
One small step in my long running quest to improve python exception handling in
LLDB.  Replace GetInteger() which just returns an int with As<long long> and
friends, which return Expected types that can track python exceptions

Reviewers: labath, jasonmolenda, JDevlieghere, vadimcn, omjavaid

Reviewed By: labath, omjavaid

Subscribers: omjavaid, lldb-commits

Tags: #lldb

Differential Revision: https://reviews.llvm.org/D78462
This commit is contained in:
Lawrence D'Anna
2020-05-08 10:56:30 -07:00
parent ae920a81ff
commit 52712d3ff7
6 changed files with 149 additions and 127 deletions

View File

@@ -44,7 +44,15 @@ template <>
Expected<long long> python::As<long long>(Expected<PythonObject> &&obj) {
if (!obj)
return obj.takeError();
return obj.get().AsLongLong();
return obj->AsLongLong();
}
template <>
Expected<unsigned long long>
python::As<unsigned long long>(Expected<PythonObject> &&obj) {
if (!obj)
return obj.takeError();
return obj->AsUnsignedLongLong();
}
template <>
@@ -61,6 +69,55 @@ Expected<std::string> python::As<std::string>(Expected<PythonObject> &&obj) {
return std::string(utf8.get());
}
Expected<long long> PythonObject::AsLongLong() const {
if (!m_py_obj)
return nullDeref();
#if PY_MAJOR_VERSION < 3
if (!PyLong_Check(m_py_obj)) {
PythonInteger i(PyRefType::Borrowed, m_py_obj);
return i.AsLongLong();
}
#endif
assert(!PyErr_Occurred());
long long r = PyLong_AsLongLong(m_py_obj);
if (PyErr_Occurred())
return exception();
return r;
}
Expected<long long> PythonObject::AsUnsignedLongLong() const {
if (!m_py_obj)
return nullDeref();
#if PY_MAJOR_VERSION < 3
if (!PyLong_Check(m_py_obj)) {
PythonInteger i(PyRefType::Borrowed, m_py_obj);
return i.AsUnsignedLongLong();
}
#endif
assert(!PyErr_Occurred());
long long r = PyLong_AsUnsignedLongLong(m_py_obj);
if (PyErr_Occurred())
return exception();
return r;
}
// wraps on overflow, instead of raising an error.
Expected<unsigned long long> PythonObject::AsModuloUnsignedLongLong() const {
if (!m_py_obj)
return nullDeref();
#if PY_MAJOR_VERSION < 3
if (!PyLong_Check(m_py_obj)) {
PythonInteger i(PyRefType::Borrowed, m_py_obj);
return i.AsModuloUnsignedLongLong();
}
#endif
assert(!PyErr_Occurred());
unsigned long long r = PyLong_AsUnsignedLongLongMask(m_py_obj);
if (PyErr_Occurred())
return exception();
return r;
}
void StructuredPythonObject::Serialize(llvm::json::OStream &s) const {
s.value(llvm::formatv("Python Obj: {0:X}", GetValue()).str());
}
@@ -463,32 +520,22 @@ void PythonInteger::Convert(PyRefType &type, PyObject *&py_obj) {
#endif
}
int64_t PythonInteger::GetInteger() const {
if (m_py_obj) {
assert(PyLong_Check(m_py_obj) &&
"PythonInteger::GetInteger has a PyObject that isn't a PyLong");
int overflow = 0;
int64_t result = PyLong_AsLongLongAndOverflow(m_py_obj, &overflow);
if (overflow != 0) {
// We got an integer that overflows, like 18446744072853913392L we can't
// use PyLong_AsLongLong() as it will return 0xffffffffffffffff. If we
// use the unsigned long long it will work as expected.
const uint64_t uval = PyLong_AsUnsignedLongLong(m_py_obj);
result = static_cast<int64_t>(uval);
}
return result;
}
return UINT64_MAX;
}
void PythonInteger::SetInteger(int64_t value) {
*this = Take<PythonInteger>(PyLong_FromLongLong(value));
}
StructuredData::IntegerSP PythonInteger::CreateStructuredInteger() const {
StructuredData::IntegerSP result(new StructuredData::Integer);
result->SetValue(GetInteger());
// FIXME this is really not ideal. Errors are silently converted to 0
// and overflows are silently wrapped. But we'd need larger changes
// to StructuredData to fix it, so that's how it is for now.
llvm::Expected<unsigned long long> value = AsModuloUnsignedLongLong();
if (!value) {
llvm::consumeError(value.takeError());
result->SetValue(0);
} else {
result->SetValue(value.get());
}
return result;
}